diff options
-rw-r--r-- | src/DotNetOpenAuth.Test/CoordinatorBase.cs | 68 | ||||
-rw-r--r-- | src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj | 11 | ||||
-rw-r--r-- | src/DotNetOpenAuth.Test/Messaging/ErrorUtilitiesTests.cs | 39 | ||||
-rw-r--r-- | src/DotNetOpenAuth.Test/Mocks/CoordinatingOAuthChannel.cs (renamed from src/DotNetOpenAuth.Test/Scenarios/CoordinatingOAuthChannel.cs) | 2 | ||||
-rw-r--r-- | src/DotNetOpenAuth.Test/OAuth/AppendixScenarios.cs (renamed from src/DotNetOpenAuth.Test/Scenarios/AppendixScenarios.cs) | 5 | ||||
-rw-r--r-- | src/DotNetOpenAuth.Test/OAuth/OAuthCoordinator.cs | 67 | ||||
-rw-r--r-- | src/DotNetOpenAuth.Test/Scenarios/Coordinator.cs | 120 | ||||
-rw-r--r-- | src/DotNetOpenAuth.sln | 2 | ||||
-rw-r--r-- | src/DotNetOpenAuth/Messaging/ErrorUtilities.cs | 26 | ||||
-rw-r--r-- | src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs | 9 | ||||
-rw-r--r-- | src/DotNetOpenAuth/Messaging/MessagingStrings.resx | 3 |
11 files changed, 224 insertions, 128 deletions
diff --git a/src/DotNetOpenAuth.Test/CoordinatorBase.cs b/src/DotNetOpenAuth.Test/CoordinatorBase.cs new file mode 100644 index 0000000..27d5930 --- /dev/null +++ b/src/DotNetOpenAuth.Test/CoordinatorBase.cs @@ -0,0 +1,68 @@ +//----------------------------------------------------------------------- +// <copyright file="CoordinatorBase.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.Test { + using System; + using System.Threading; + using DotNetOpenAuth.Messaging; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + internal abstract class CoordinatorBase<T1, T2> { + private Action<T1> party1Action; + private Action<T2> party2Action; + + protected CoordinatorBase(Action<T1> party1Action, Action<T2> party2Action) { + ErrorUtilities.VerifyArgumentNotNull(party1Action, "party1Action"); + ErrorUtilities.VerifyArgumentNotNull(party2Action, "party2Action"); + + this.party1Action = party1Action; + this.party2Action = party2Action; + } + + protected void RunCore(T1 party1Object, T2 party2Object) { + Thread party1Thread = null, party2Thread = null; + Exception failingException = null; + + // Each thread we create needs a surrounding exception catcher so that we can + // terminate the other thread and inform the test host that the test failed. + Action<Action> safeWrapper = (action) => { + try { + action(); + } catch (Exception ex) { + // We may be the second thread in an ThreadAbortException, so check the "flag" + if (failingException == null) { + failingException = ex; + if (Thread.CurrentThread == party1Thread) { + party2Thread.Abort(); + } else { + party1Thread.Abort(); + } + } + } + }; + + // Run the threads, and wait for them to complete. + // If this main thread is aborted (test run aborted), go ahead and abort the other two threads. + party1Thread = new Thread(() => { safeWrapper(() => { this.party1Action(party1Object); }); }); + party2Thread = new Thread(() => { safeWrapper(() => { this.party2Action(party2Object); }); }); + try { + party1Thread.Start(); + party2Thread.Start(); + party1Thread.Join(); + party2Thread.Join(); + } catch (ThreadAbortException) { + party1Thread.Abort(); + party2Thread.Abort(); + throw; + } + + // Use the failing reason of a failing sub-thread as our reason, if anything failed. + if (failingException != null) { + throw new AssertFailedException("Coordinator thread threw unhandled exception: " + failingException, failingException); + } + } + } +} diff --git a/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj b/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj index b580064..d4b3b56 100644 --- a/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj +++ b/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj @@ -58,7 +58,9 @@ </Reference> </ItemGroup> <ItemGroup> + <Compile Include="CoordinatorBase.cs" /> <Compile Include="Messaging\CollectionAssert.cs" /> + <Compile Include="Messaging\ErrorUtilitiesTests.cs" /> <Compile Include="Messaging\MessageSerializerTests.cs" /> <Compile Include="Messaging\Reflection\MessageDescriptionTests.cs" /> <Compile Include="Messaging\Reflection\MessageDictionaryTests.cs" /> @@ -102,9 +104,9 @@ <Compile Include="OpenId\Messages\IndirectErrorResponseTests.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Messaging\ResponseTests.cs" /> - <Compile Include="Scenarios\AppendixScenarios.cs" /> - <Compile Include="Scenarios\CoordinatingOAuthChannel.cs" /> - <Compile Include="Scenarios\Coordinator.cs" /> + <Compile Include="OAuth\AppendixScenarios.cs" /> + <Compile Include="Mocks\CoordinatingOAuthChannel.cs" /> + <Compile Include="OAuth\OAuthCoordinator.cs" /> <Compile Include="TestBase.cs" /> <Compile Include="TestUtilities.cs" /> <Compile Include="UriUtilTests.cs" /> @@ -121,6 +123,9 @@ <ItemGroup> <Shadow Include="Test References\DotNetOpenAuth.accessor" /> </ItemGroup> + <ItemGroup> + <Folder Include="Scenarios\" /> + </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="..\..\tools\DotNetOpenAuth.Versioning.targets" /> </Project>
\ No newline at end of file diff --git a/src/DotNetOpenAuth.Test/Messaging/ErrorUtilitiesTests.cs b/src/DotNetOpenAuth.Test/Messaging/ErrorUtilitiesTests.cs new file mode 100644 index 0000000..36b6ae7 --- /dev/null +++ b/src/DotNetOpenAuth.Test/Messaging/ErrorUtilitiesTests.cs @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------- +// <copyright file="ErrorUtilitiesTests.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.Test.Messaging { + using System; + using DotNetOpenAuth.Messaging; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class ErrorUtilitiesTests { + [TestMethod, ExpectedException(typeof(ArgumentNullException))] + public void VerifyArgumentNotNullThrows() { + ErrorUtilities.VerifyArgumentNotNull(null, "someArg"); + } + + [TestMethod] + public void VerifyArgumentNotNullDoesNotThrow() { + ErrorUtilities.VerifyArgumentNotNull("hi", "someArg"); + } + + [TestMethod, ExpectedException(typeof(ArgumentNullException))] + public void VerifyNonZeroLengthOnNull() { + ErrorUtilities.VerifyNonZeroLength(null, "someArg"); + } + + [TestMethod, ExpectedException(typeof(ArgumentException))] + public void VerifyNonZeroLengthOnEmpty() { + ErrorUtilities.VerifyNonZeroLength(string.Empty, "someArg"); + } + + [TestMethod] + public void VerifyNonZeroLengthOnNonEmpty() { + ErrorUtilities.VerifyNonZeroLength("some Value", "someArg"); + } + } +} diff --git a/src/DotNetOpenAuth.Test/Scenarios/CoordinatingOAuthChannel.cs b/src/DotNetOpenAuth.Test/Mocks/CoordinatingOAuthChannel.cs index 0fa474e..ce45572 100644 --- a/src/DotNetOpenAuth.Test/Scenarios/CoordinatingOAuthChannel.cs +++ b/src/DotNetOpenAuth.Test/Mocks/CoordinatingOAuthChannel.cs @@ -4,7 +4,7 @@ // </copyright> //----------------------------------------------------------------------- -namespace DotNetOpenAuth.Test.Scenarios { +namespace DotNetOpenAuth.Test.Mocks { using System; using System.Threading; using DotNetOpenAuth.Messaging; diff --git a/src/DotNetOpenAuth.Test/Scenarios/AppendixScenarios.cs b/src/DotNetOpenAuth.Test/OAuth/AppendixScenarios.cs index 5fb7538..5d25cf9 100644 --- a/src/DotNetOpenAuth.Test/Scenarios/AppendixScenarios.cs +++ b/src/DotNetOpenAuth.Test/OAuth/AppendixScenarios.cs @@ -4,7 +4,7 @@ // </copyright> //----------------------------------------------------------------------- -namespace DotNetOpenAuth.Test { +namespace DotNetOpenAuth.Test.OAuth { using System; using System.IO; using System.Net; @@ -12,7 +12,6 @@ namespace DotNetOpenAuth.Test { using DotNetOpenAuth.OAuth; using DotNetOpenAuth.OAuth.ChannelElements; using DotNetOpenAuth.Test.Mocks; - using DotNetOpenAuth.Test.Scenarios; using Microsoft.VisualStudio.TestTools.UnitTesting; [TestClass] @@ -31,7 +30,7 @@ namespace DotNetOpenAuth.Test { MessageReceivingEndpoint accessPhotoEndpoint = new MessageReceivingEndpoint("http://photos.example.net/photos?file=vacation.jpg&size=original", HttpDeliveryMethods.AuthorizationHeaderRequest | HttpDeliveryMethods.GetRequest); ConsumerDescription consumerDescription = new ConsumerDescription("dpf43f3p2l4k3l03", "kd94hf93k423kf44"); - Coordinator coordinator = new Coordinator( + OAuthCoordinator coordinator = new OAuthCoordinator( consumerDescription, serviceDescription, consumer => { diff --git a/src/DotNetOpenAuth.Test/OAuth/OAuthCoordinator.cs b/src/DotNetOpenAuth.Test/OAuth/OAuthCoordinator.cs new file mode 100644 index 0000000..37d7e5b --- /dev/null +++ b/src/DotNetOpenAuth.Test/OAuth/OAuthCoordinator.cs @@ -0,0 +1,67 @@ +//----------------------------------------------------------------------- +// <copyright file="OAuthCoordinator.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.Test { + using System; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OAuth; + using DotNetOpenAuth.Test.Mocks; + + /// <summary> + /// Runs a Consumer and Service Provider simultaneously so they can interact in a full simulation. + /// </summary> + internal class OAuthCoordinator : CoordinatorBase<WebConsumer, ServiceProvider> { + private ConsumerDescription consumerDescription; + private ServiceProviderDescription serviceDescription; + + /// <summary>Initializes a new instance of the <see cref="OAuthCoordinator"/> class.</summary> + /// <param name="consumerDescription">The description of the consumer.</param> + /// <param name="serviceDescription">The service description that will be used to construct the Consumer and ServiceProvider objects.</param> + /// <param name="consumerAction">The code path of the Consumer.</param> + /// <param name="serviceProviderAction">The code path of the Service Provider.</param> + internal OAuthCoordinator(ConsumerDescription consumerDescription, ServiceProviderDescription serviceDescription, Action<WebConsumer> consumerAction, Action<ServiceProvider> serviceProviderAction) + : base(consumerAction, serviceProviderAction) { + ErrorUtilities.VerifyArgumentNotNull(consumerDescription, "consumerDescription"); + ErrorUtilities.VerifyArgumentNotNull(serviceDescription, "serviceDescription"); + + this.consumerDescription = consumerDescription; + this.serviceDescription = serviceDescription; + } + + /// <summary> + /// Starts the simulation. + /// </summary> + internal void Run() { + // Clone the template signing binding element. + var signingElement = this.serviceDescription.CreateTamperProtectionElement(); + var consumerSigningElement = signingElement.Clone(); + var spSigningElement = signingElement.Clone(); + + // Prepare token managers + InMemoryTokenManager consumerTokenManager = new InMemoryTokenManager(); + InMemoryTokenManager serviceTokenManager = new InMemoryTokenManager(); + consumerTokenManager.AddConsumer(this.consumerDescription); + serviceTokenManager.AddConsumer(this.consumerDescription); + + // Prepare channels that will pass messages directly back and forth. + CoordinatingOAuthChannel consumerChannel = new CoordinatingOAuthChannel(consumerSigningElement, true, consumerTokenManager); + CoordinatingOAuthChannel serviceProviderChannel = new CoordinatingOAuthChannel(spSigningElement, false, serviceTokenManager); + consumerChannel.RemoteChannel = serviceProviderChannel; + serviceProviderChannel.RemoteChannel = consumerChannel; + + // Prepare the Consumer and Service Provider objects + WebConsumer consumer = new WebConsumer(this.serviceDescription, consumerTokenManager) { + OAuthChannel = consumerChannel, + ConsumerKey = this.consumerDescription.ConsumerKey, + }; + ServiceProvider serviceProvider = new ServiceProvider(this.serviceDescription, serviceTokenManager) { + OAuthChannel = serviceProviderChannel, + }; + + this.RunCore(consumer, serviceProvider); + } + } +} diff --git a/src/DotNetOpenAuth.Test/Scenarios/Coordinator.cs b/src/DotNetOpenAuth.Test/Scenarios/Coordinator.cs deleted file mode 100644 index 0479092..0000000 --- a/src/DotNetOpenAuth.Test/Scenarios/Coordinator.cs +++ /dev/null @@ -1,120 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="Coordinator.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.Test.Scenarios { - using System; - using System.Threading; - using DotNetOpenAuth.OAuth; - using DotNetOpenAuth.Test.Mocks; - using Microsoft.VisualStudio.TestTools.UnitTesting; - - /// <summary> - /// Runs a Consumer and Service Provider simultaneously so they can interact in a full simulation. - /// </summary> - internal class Coordinator { - private ConsumerDescription consumerDescription; - private ServiceProviderDescription serviceDescription; - private Action<WebConsumer> consumerAction; - private Action<ServiceProvider> serviceProviderAction; - - /// <summary>Initializes a new instance of the <see cref="Coordinator"/> class.</summary> - /// <param name="consumerDescription">The description of the consumer.</param> - /// <param name="serviceDescription">The service description that will be used to construct the Consumer and ServiceProvider objects.</param> - /// <param name="consumerAction">The code path of the Consumer.</param> - /// <param name="serviceProviderAction">The code path of the Service Provider.</param> - internal Coordinator(ConsumerDescription consumerDescription, ServiceProviderDescription serviceDescription, Action<WebConsumer> consumerAction, Action<ServiceProvider> serviceProviderAction) { - if (consumerDescription == null) { - throw new ArgumentNullException("consumerDescription"); - } - if (serviceDescription == null) { - throw new ArgumentNullException("serviceDescription"); - } - if (consumerAction == null) { - throw new ArgumentNullException("consumerAction"); - } - if (serviceProviderAction == null) { - throw new ArgumentNullException("serviceProviderAction"); - } - - this.consumerDescription = consumerDescription; - this.serviceDescription = serviceDescription; - this.consumerAction = consumerAction; - this.serviceProviderAction = serviceProviderAction; - } - - /// <summary> - /// Starts the simulation. - /// </summary> - internal void Run() { - // Clone the template signing binding element. - var signingElement = this.serviceDescription.CreateTamperProtectionElement(); - var consumerSigningElement = signingElement.Clone(); - var spSigningElement = signingElement.Clone(); - - // Prepare token managers - InMemoryTokenManager consumerTokenManager = new InMemoryTokenManager(); - InMemoryTokenManager serviceTokenManager = new InMemoryTokenManager(); - consumerTokenManager.AddConsumer(this.consumerDescription); - serviceTokenManager.AddConsumer(this.consumerDescription); - - // Prepare channels that will pass messages directly back and forth. - CoordinatingOAuthChannel consumerChannel = new CoordinatingOAuthChannel(consumerSigningElement, true, consumerTokenManager); - CoordinatingOAuthChannel serviceProviderChannel = new CoordinatingOAuthChannel(spSigningElement, false, serviceTokenManager); - consumerChannel.RemoteChannel = serviceProviderChannel; - serviceProviderChannel.RemoteChannel = consumerChannel; - - // Prepare the Consumer and Service Provider objects - WebConsumer consumer = new WebConsumer(this.serviceDescription, consumerTokenManager) { - OAuthChannel = consumerChannel, - ConsumerKey = this.consumerDescription.ConsumerKey, - }; - ServiceProvider serviceProvider = new ServiceProvider(this.serviceDescription, serviceTokenManager) { - OAuthChannel = serviceProviderChannel, - }; - - Thread consumerThread = null, serviceProviderThread = null; - Exception failingException = null; - - // Each thread we create needs a surrounding exception catcher so that we can - // terminate the other thread and inform the test host that the test failed. - Action<Action> safeWrapper = (action) => { - try { - action(); - } catch (Exception ex) { - // We may be the second thread in an ThreadAbortException, so check the "flag" - if (failingException == null) { - failingException = ex; - if (Thread.CurrentThread == consumerThread) { - serviceProviderThread.Abort(); - } else { - consumerThread.Abort(); - } - } - } - }; - - // Run the threads, and wait for them to complete. - // If this main thread is aborted (test run aborted), go ahead and abort the other two threads. - consumerThread = new Thread(() => { safeWrapper(() => { consumerAction(consumer); }); }); - serviceProviderThread = new Thread(() => { safeWrapper(() => { serviceProviderAction(serviceProvider); }); }); - try { - consumerThread.Start(); - serviceProviderThread.Start(); - consumerThread.Join(); - serviceProviderThread.Join(); - } catch (ThreadAbortException) { - consumerThread.Abort(); - serviceProviderThread.Abort(); - throw; - } - - // Use the failing reason of a failing sub-thread as our reason, if anything failed. - if (failingException != null) { - throw new AssertFailedException("Coordinator thread threw unhandled exception: " + failingException, failingException); - } - } - } -} diff --git a/src/DotNetOpenAuth.sln b/src/DotNetOpenAuth.sln index e636d1b..6707b28 100644 --- a/src/DotNetOpenAuth.sln +++ b/src/DotNetOpenAuth.sln @@ -63,7 +63,7 @@ Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "ServiceProvider", "..\sampl Release.AspNetCompiler.ForceOverwrite = "true" Release.AspNetCompiler.FixedNames = "false" Release.AspNetCompiler.Debug = "False" - VWDPort = "65169" + VWDPort = "37480" DefaultWebSiteLanguage = "Visual C#" EndProjectSection EndProject diff --git a/src/DotNetOpenAuth/Messaging/ErrorUtilities.cs b/src/DotNetOpenAuth/Messaging/ErrorUtilities.cs index b16cb0e..8464066 100644 --- a/src/DotNetOpenAuth/Messaging/ErrorUtilities.cs +++ b/src/DotNetOpenAuth/Messaging/ErrorUtilities.cs @@ -50,5 +50,31 @@ namespace DotNetOpenAuth.Messaging { args)); } } + + /// <summary> + /// Verifies that some given value is not null. + /// </summary> + /// <param name="value">The value to check.</param> + /// <param name="paramName">Name of the parameter, which will be used in the <see cref="ArgumentException"/>, if thrown.</param> + /// <exception cref="ArgumentNullException">Thrown if <paramref name="value"/> is null.</exception> + internal static void VerifyArgumentNotNull(object value, string paramName) { + if (Object.ReferenceEquals(value, null)) { + throw new ArgumentNullException(paramName); + } + } + + /// <summary> + /// Verifies that some string is not null and has non-zero length. + /// </summary> + /// <param name="value">The value to check.</param> + /// <param name="paramName">Name of the parameter, which will be used in the <see cref="ArgumentException"/>, if thrown.</param> + /// <exception cref="ArgumentNullException">Thrown if <paramref name="value"/> is null.</exception> + /// <exception cref="ArgumentException">Thrown if <paramref name="value"/> has zero length.</exception> + internal static void VerifyNonZeroLength(string value, string paramName) { + VerifyArgumentNotNull(value, paramName); + if (value.Length == 0) { + throw new ArgumentException(MessagingStrings.UnexpectedEmptyString, paramName); + } + } } } diff --git a/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs b/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs index 5733fc9..cd3cba1 100644 --- a/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs +++ b/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs @@ -376,6 +376,15 @@ namespace DotNetOpenAuth.Messaging { } /// <summary> + /// Looks up a localized string similar to The empty string is not allowed.. + /// </summary> + internal static string UnexpectedEmptyString { + get { + return ResourceManager.GetString("UnexpectedEmptyString", resourceCulture); + } + } + + /// <summary> /// Looks up a localized string similar to Message parameter '{0}' had unexpected value '{1}'.. /// </summary> internal static string UnexpectedMessagePartValue { diff --git a/src/DotNetOpenAuth/Messaging/MessagingStrings.resx b/src/DotNetOpenAuth/Messaging/MessagingStrings.resx index 262d084..5f5b9b4 100644 --- a/src/DotNetOpenAuth/Messaging/MessagingStrings.resx +++ b/src/DotNetOpenAuth/Messaging/MessagingStrings.resx @@ -222,6 +222,9 @@ <data name="TooManyBindingsOfferingSameProtection" xml:space="preserve"> <value>Expected at most 1 binding element offering the {0} protection, but found {1}.</value> </data> + <data name="UnexpectedEmptyString" xml:space="preserve"> + <value>The empty string is not allowed.</value> + </data> <data name="UnexpectedMessagePartValue" xml:space="preserve"> <value>Message parameter '{0}' had unexpected value '{1}'.</value> </data> |