From 2b041710226f6ff3959d243b047ba64ab7db9a9b Mon Sep 17 00:00:00 2001 From: Andrei Grigorev Date: Tue, 10 Oct 2017 16:26:18 -0700 Subject: [PATCH] Adding the ability to schedule validation message processing in the future (#69) * Added ScheduledEnqueueTimeUtc to the IBrokeredMessage and implementation. Added tests for the property * Added the postponed version of the StartValidationAsync to the IPackageValidationEnqueuer --- NuGet.Server.Common.sln | 9 ++- .../ServiceBus/IBrokeredMessage.cs | 1 + .../BrokeredMessageWrapper.cs | 6 ++ .../IPackageValidationEnqueuer.cs | 12 ++++ .../PackageValidationEnqueuer.cs | 7 +++ .../BrokeredMessageWrapperFacts.cs | 51 ++++++++++++++++ .../NuGet.Services.ServiceBus.Tests.csproj | 59 +++++++++++++++++++ .../Properties/AssemblyInfo.cs | 14 +++++ .../project.json | 14 +++++ 9 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 tests/NuGet.Services.ServiceBus.Tests/BrokeredMessageWrapperFacts.cs create mode 100644 tests/NuGet.Services.ServiceBus.Tests/NuGet.Services.ServiceBus.Tests.csproj create mode 100644 tests/NuGet.Services.ServiceBus.Tests/Properties/AssemblyInfo.cs create mode 100644 tests/NuGet.Services.ServiceBus.Tests/project.json diff --git a/NuGet.Server.Common.sln b/NuGet.Server.Common.sln index 9a828dbc..5d261453 100644 --- a/NuGet.Server.Common.sln +++ b/NuGet.Server.Common.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26730.0 +VisualStudioVersion = 15.0.27005.2 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8415FED7-1BED-4227-8B4F-BB7C24E041CD}" EndProject @@ -50,6 +50,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuGet.Services.Validation.T EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuGet.Services.Contracts.Tests", "tests\NuGet.Services.Contracts.Tests\NuGet.Services.Contracts.Tests.csproj", "{79F72C83-E94D-4D04-B904-5A4DA161168E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuGet.Services.ServiceBus.Tests", "tests\NuGet.Services.ServiceBus.Tests\NuGet.Services.ServiceBus.Tests.csproj", "{FF5CA51A-CD6A-463F-AE9A-5737FF0FCFA7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -132,6 +134,10 @@ Global {79F72C83-E94D-4D04-B904-5A4DA161168E}.Debug|Any CPU.Build.0 = Debug|Any CPU {79F72C83-E94D-4D04-B904-5A4DA161168E}.Release|Any CPU.ActiveCfg = Release|Any CPU {79F72C83-E94D-4D04-B904-5A4DA161168E}.Release|Any CPU.Build.0 = Release|Any CPU + {FF5CA51A-CD6A-463F-AE9A-5737FF0FCFA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FF5CA51A-CD6A-463F-AE9A-5737FF0FCFA7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FF5CA51A-CD6A-463F-AE9A-5737FF0FCFA7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FF5CA51A-CD6A-463F-AE9A-5737FF0FCFA7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -156,6 +162,7 @@ Global {C1E36A2C-1C1B-4521-B256-AD42505D9EFB} = {8415FED7-1BED-4227-8B4F-BB7C24E041CD} {E29F54DF-DFB8-4E27-940D-21ECCB9B6FC1} = {7783A106-0F4C-4055-9AB4-413FB2C7B8F0} {79F72C83-E94D-4D04-B904-5A4DA161168E} = {7783A106-0F4C-4055-9AB4-413FB2C7B8F0} + {FF5CA51A-CD6A-463F-AE9A-5737FF0FCFA7} = {7783A106-0F4C-4055-9AB4-413FB2C7B8F0} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AA413DB0-5475-4B5D-A3AF-6323DA8D538B} diff --git a/src/NuGet.Services.Contracts/ServiceBus/IBrokeredMessage.cs b/src/NuGet.Services.Contracts/ServiceBus/IBrokeredMessage.cs index 8aedbb44..f953bed4 100644 --- a/src/NuGet.Services.Contracts/ServiceBus/IBrokeredMessage.cs +++ b/src/NuGet.Services.Contracts/ServiceBus/IBrokeredMessage.cs @@ -10,6 +10,7 @@ namespace NuGet.Services.ServiceBus public interface IBrokeredMessage : IDisposable { IDictionary Properties { get; } + DateTimeOffset ScheduledEnqueueTimeUtc { get; set; } Task CompleteAsync(); string GetBody(); IBrokeredMessage Clone(); diff --git a/src/NuGet.Services.ServiceBus/BrokeredMessageWrapper.cs b/src/NuGet.Services.ServiceBus/BrokeredMessageWrapper.cs index 905ca88e..034312a9 100644 --- a/src/NuGet.Services.ServiceBus/BrokeredMessageWrapper.cs +++ b/src/NuGet.Services.ServiceBus/BrokeredMessageWrapper.cs @@ -24,6 +24,12 @@ public BrokeredMessageWrapper(BrokeredMessage brokeredMessage) public IDictionary Properties => BrokeredMessage.Properties; + public DateTimeOffset ScheduledEnqueueTimeUtc + { + get => new DateTimeOffset(BrokeredMessage.ScheduledEnqueueTimeUtc); + set => BrokeredMessage.ScheduledEnqueueTimeUtc = new DateTime(value.UtcTicks, DateTimeKind.Utc); + } + public string GetBody() { return BrokeredMessage.GetBody(); diff --git a/src/NuGet.Services.Validation/IPackageValidationEnqueuer.cs b/src/NuGet.Services.Validation/IPackageValidationEnqueuer.cs index 84cd3247..4b8f6434 100644 --- a/src/NuGet.Services.Validation/IPackageValidationEnqueuer.cs +++ b/src/NuGet.Services.Validation/IPackageValidationEnqueuer.cs @@ -1,12 +1,24 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Threading.Tasks; namespace NuGet.Services.Validation { public interface IPackageValidationEnqueuer { + /// + /// Enqueues validation of the specified package to start ASAP. + /// + /// Package information Task StartValidationAsync(PackageValidationMessageData message); + + /// + /// Enqueues validation of the specified package to start no sooner than specified time + /// + /// Package information + /// The time till which validation processing should be postponed. + Task StartValidationAsync(PackageValidationMessageData message, DateTimeOffset postponeProcessingTill); } } diff --git a/src/NuGet.Services.Validation/PackageValidationEnqueuer.cs b/src/NuGet.Services.Validation/PackageValidationEnqueuer.cs index 8d0d5d6d..8fab2dad 100644 --- a/src/NuGet.Services.Validation/PackageValidationEnqueuer.cs +++ b/src/NuGet.Services.Validation/PackageValidationEnqueuer.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Threading.Tasks; using NuGet.Services.ServiceBus; @@ -18,8 +19,14 @@ public PackageValidationEnqueuer(ITopicClient topicClient, IServiceBusMessageSer } public async Task StartValidationAsync(PackageValidationMessageData message) + { + await StartValidationAsync(message, DateTimeOffset.MinValue); + } + + public async Task StartValidationAsync(PackageValidationMessageData message, DateTimeOffset postponeProcessingTill) { var brokeredMessage = _serializer.SerializePackageValidationMessageData(message); + brokeredMessage.ScheduledEnqueueTimeUtc = postponeProcessingTill; await _topicClient.SendAsync(brokeredMessage); } } diff --git a/tests/NuGet.Services.ServiceBus.Tests/BrokeredMessageWrapperFacts.cs b/tests/NuGet.Services.ServiceBus.Tests/BrokeredMessageWrapperFacts.cs new file mode 100644 index 00000000..97a2e560 --- /dev/null +++ b/tests/NuGet.Services.ServiceBus.Tests/BrokeredMessageWrapperFacts.cs @@ -0,0 +1,51 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Xunit; + +namespace NuGet.Services.ServiceBus.Tests +{ + public class BrokeredMessageWrapperFacts + { + [Fact] + public void DoesNotMessUpScheduledEnqueueTimeUtc() + { + var now = DateTimeOffset.Now; + + var message = new BrokeredMessageWrapper("data"); + message.ScheduledEnqueueTimeUtc = now; + Assert.Equal(now, message.ScheduledEnqueueTimeUtc); + } + + [Fact] + public void ForcesUtcOnScheduledEnqueueTimeUtc() + { + var now = DateTimeOffset.Now; + var nowUtc = now.UtcDateTime; + + var message = new BrokeredMessageWrapper("data"); + message.ScheduledEnqueueTimeUtc = now; + + Assert.Equal(DateTimeKind.Utc, message.BrokeredMessage.ScheduledEnqueueTimeUtc.Kind); + Assert.Equal(nowUtc, message.BrokeredMessage.ScheduledEnqueueTimeUtc); + Assert.Equal(TimeSpan.Zero, message.ScheduledEnqueueTimeUtc.Offset); + } + + [Fact] + public void DefaultScheduledEnqueueTimeUtcIsNotInTheFuture() + { + var message = new BrokeredMessageWrapper("data"); + Assert.True(message.ScheduledEnqueueTimeUtc <= DateTimeOffset.Now); + } + + [Fact] + public void MinScheduledEnqueueTimeUtcWorks() + { + var message = new BrokeredMessageWrapper("data"); + message.ScheduledEnqueueTimeUtc = DateTimeOffset.MinValue; + + Assert.True(message.ScheduledEnqueueTimeUtc < DateTimeOffset.Now); + } + } +} diff --git a/tests/NuGet.Services.ServiceBus.Tests/NuGet.Services.ServiceBus.Tests.csproj b/tests/NuGet.Services.ServiceBus.Tests/NuGet.Services.ServiceBus.Tests.csproj new file mode 100644 index 00000000..67f1efaf --- /dev/null +++ b/tests/NuGet.Services.ServiceBus.Tests/NuGet.Services.ServiceBus.Tests.csproj @@ -0,0 +1,59 @@ + + + + + Debug + AnyCPU + {FF5CA51A-CD6A-463F-AE9A-5737FF0FCFA7} + Library + Properties + NuGet.Services.ServiceBus.Tests + NuGet.Services.ServiceBus.Tests + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + {9337000b-ea3b-40be-9a33-38bc28dfd0cb} + NuGet.Services.ServiceBus + + + + \ No newline at end of file diff --git a/tests/NuGet.Services.ServiceBus.Tests/Properties/AssemblyInfo.cs b/tests/NuGet.Services.ServiceBus.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..e394674b --- /dev/null +++ b/tests/NuGet.Services.ServiceBus.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,14 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("NuGet.Services.ServiceBus.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("NuGet.Services.ServiceBus.Tests")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: ComVisible(false)] +[assembly: Guid("ff5ca51a-cd6a-463f-ae9a-5737ff0fcfa7")] diff --git a/tests/NuGet.Services.ServiceBus.Tests/project.json b/tests/NuGet.Services.ServiceBus.Tests/project.json new file mode 100644 index 00000000..42de3faf --- /dev/null +++ b/tests/NuGet.Services.ServiceBus.Tests/project.json @@ -0,0 +1,14 @@ +{ + "dependencies": { + "WindowsAzure.ServiceBus": "4.1.3", + "Moq": "4.5.23", + "xunit": "2.1.0", + "xunit.runner.visualstudio": "2.1.0" + }, + "frameworks": { + "net452": {} + }, + "runtimes": { + "win": {} + } +} \ No newline at end of file