//----------------------------------------------------------------------- // // Copyright (c) Andrew Arnott. All rights reserved. // //----------------------------------------------------------------------- namespace DotNetOpenAuth.Test.OpenId.Provider { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Text; using DotNetOpenAuth.Messaging; using DotNetOpenAuth.Messaging.Reflection; using DotNetOpenAuth.OpenId; using DotNetOpenAuth.OpenId.ChannelElements; using DotNetOpenAuth.OpenId.Messages; using DotNetOpenAuth.OpenId.Provider; using NUnit.Framework; [TestFixture, Category("Performance")] public class PerformanceTests : OpenIdTestBase { private const string SharedAssociationHandle = "handle"; private static readonly TimeSpan TestRunTime = TimeSpan.FromSeconds(3); private OpenIdProvider provider; [SetUp] public override void SetUp() { base.SetUp(); SuspendLogging(); this.provider = CreateProvider(); } [TearDown] public override void Cleanup() { ResumeLogging(); base.Cleanup(); } [TestCase] public void AssociateDH() { var associateRequest = this.CreateAssociateRequest(OPUri); Stopwatch timer = new Stopwatch(); timer.Start(); int iterations; for (iterations = 0; timer.ElapsedMilliseconds < TestRunTime.TotalMilliseconds; iterations++) { IRequest request = this.provider.GetRequest(associateRequest); var response = this.provider.PrepareResponse(request); Assert.IsInstanceOf(response.OriginalMessage); } timer.Stop(); double executionsPerSecond = GetExecutionsPerSecond(iterations, timer); TestUtilities.TestLogger.InfoFormat("Created {0} associations in {1}, or {2} per second.", iterations, timer.Elapsed, executionsPerSecond); Assert.IsTrue(executionsPerSecond >= 2, "Too slow ({0} >= 2 executions per second required.)", executionsPerSecond); } [TestCase] public void AssociateClearText() { var associateRequest = this.CreateAssociateRequest(OPUriSsl); // SSL will cause a plaintext association Stopwatch timer = new Stopwatch(); timer.Start(); int iterations; for (iterations = 0; timer.ElapsedMilliseconds < TestRunTime.TotalMilliseconds; iterations++) { IRequest request = this.provider.GetRequest(associateRequest); var response = this.provider.PrepareResponse(request); Assert.IsInstanceOf(response.OriginalMessage); } timer.Stop(); double executionsPerSecond = GetExecutionsPerSecond(iterations, timer); TestUtilities.TestLogger.InfoFormat("Created {0} associations in {1}, or {2} per second.", iterations, timer.Elapsed, executionsPerSecond); Assert.IsTrue(executionsPerSecond > 1000, "Too slow ({0} > 1000 executions per second required.)", executionsPerSecond); } [TestCase] public void CheckIdSharedHmacSha1Association() { Protocol protocol = Protocol.Default; string assocType = protocol.Args.SignatureAlgorithm.HMAC_SHA1; double executionsPerSecond = this.ParameterizedCheckIdTest(protocol, assocType); TestUtilities.TestLogger.InfoFormat("{0} executions per second.", executionsPerSecond); Assert.IsTrue(executionsPerSecond > 500, "Too slow ({0} > 500 executions per second required.)", executionsPerSecond); } [TestCase] public void CheckIdSharedHmacSha256Association() { Protocol protocol = Protocol.Default; string assocType = protocol.Args.SignatureAlgorithm.HMAC_SHA256; double executionsPerSecond = this.ParameterizedCheckIdTest(protocol, assocType); TestUtilities.TestLogger.InfoFormat("{0} executions per second.", executionsPerSecond); Assert.IsTrue(executionsPerSecond > 400, "Too slow ({0} > 400 executions per second required.)", executionsPerSecond); } private static double GetExecutionsPerSecond(int iterations, Stopwatch timer) { return (double)iterations / (timer.ElapsedMilliseconds / 1000); } private double ParameterizedCheckIdTest(Protocol protocol, string assocType) { Association assoc = HmacShaAssociation.Create( protocol, assocType, AssociationRelyingPartyType.Smart, this.provider.SecuritySettings); this.provider.AssociationStore.StoreAssociation(AssociationRelyingPartyType.Smart, assoc); var checkidRequest = this.CreateCheckIdRequest(true); Stopwatch timer = new Stopwatch(); timer.Start(); int iterations; for (iterations = 0; timer.ElapsedMilliseconds < TestRunTime.TotalMilliseconds; iterations++) { var request = (IAuthenticationRequest)this.provider.GetRequest(checkidRequest); request.IsAuthenticated = true; var response = this.provider.PrepareResponse(request); Assert.IsInstanceOf(response.OriginalMessage); } timer.Stop(); double executionsPerSecond = GetExecutionsPerSecond(iterations, timer); TestUtilities.TestLogger.InfoFormat("Responded to {0} checkid messages in {1}; or {2} authentications per second.", iterations, timer.Elapsed, executionsPerSecond); return executionsPerSecond; } private HttpRequestInfo CreateAssociateRequest(Uri opEndpoint) { var rp = CreateRelyingParty(true); AssociateRequest associateMessage = AssociateRequest.Create(rp.SecuritySettings, new ProviderEndpointDescription(opEndpoint, Protocol.Default.Version)); Channel rpChannel = rp.Channel; MemoryStream ms = new MemoryStream(); StreamWriter mswriter = new StreamWriter(ms); mswriter.Write(MessagingUtilities.CreateQueryString(rpChannel.MessageDescriptions.GetAccessor(associateMessage))); mswriter.Flush(); ms.Position = 0; var headers = new WebHeaderCollection(); headers.Add(HttpRequestHeader.ContentType, Channel.HttpFormUrlEncoded); var httpRequest = new HttpRequestInfo("POST", opEndpoint, opEndpoint.PathAndQuery, headers, ms); return httpRequest; } private HttpRequestInfo CreateCheckIdRequest(bool sharedAssociation) { var rp = CreateRelyingParty(true); CheckIdRequest checkidMessage = new CheckIdRequest( Protocol.Default.Version, OPUri, DotNetOpenAuth.OpenId.RelyingParty.AuthenticationRequestMode.Setup); if (sharedAssociation) { checkidMessage.AssociationHandle = SharedAssociationHandle; } checkidMessage.ClaimedIdentifier = OPLocalIdentifiers[0]; checkidMessage.LocalIdentifier = OPLocalIdentifiers[0]; checkidMessage.Realm = RPRealmUri; checkidMessage.ReturnTo = RPUri; Channel rpChannel = rp.Channel; UriBuilder receiver = new UriBuilder(OPUri); receiver.Query = MessagingUtilities.CreateQueryString(rpChannel.MessageDescriptions.GetAccessor(checkidMessage)); var headers = new WebHeaderCollection(); var httpRequest = new HttpRequestInfo("GET", receiver.Uri, receiver.Uri.PathAndQuery, headers, null); return httpRequest; } } }