Skip to content

Commit 6fe3329

Browse files
authored
Make start-up and infrastructure code more testable and add two basic integration tests (#31)
1 parent 6dd6a8e commit 6fe3329

19 files changed

Lines changed: 434 additions & 64 deletions

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,4 +206,6 @@ DebugConstants.cs
206206
src/VsExtension/source.extension.vsixmanifest
207207
!packages/Microsoft.Web.Xdt.1.0.0-alpha/
208208
src/NuGet.Server/packages/*.bin
209-
*.cache.bin
209+
*.cache.bin
210+
211+
!**/TestData/*.nupkg

src/NuGet.Server.Core/Infrastructure/ServerPackageRepository.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ private async Task<SuppressedFileSystemWatcher> LockAndSuppressFileSystemWatcher
608608
/// A disposable type that wraps a semaphore so dispose releases the semaphore. This allows for more ergonomic
609609
/// used (such as in a <code>using</code> statement).
610610
/// </summary>
611-
private class Lock : IDisposable
611+
private sealed class Lock : IDisposable
612612
{
613613
private readonly SemaphoreSlim _semaphore;
614614
private bool _lockTaken;
@@ -636,7 +636,7 @@ public void Dispose()
636636
}
637637
}
638638

639-
private class SuppressedFileSystemWatcher : IDisposable
639+
private sealed class SuppressedFileSystemWatcher : IDisposable
640640
{
641641
private readonly ServerPackageRepository _repository;
642642
private Lock _lockHandle;

src/NuGet.Server/App_Start/NuGetODataConfig.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
2-
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
34
using System.Net.Http;
45
using System.Web.Http;
56
using System.Web.Http.Routing;
7+
using NuGet.Server.DataServices;
68
using NuGet.Server.V2;
79

810
// The consuming project executes this logic with its own copy of this class. This is done with a .pp file that is
@@ -19,17 +21,19 @@ public static void Start()
1921
{
2022
ServiceResolver.SetServiceResolver(new DefaultServiceResolver());
2123

22-
var config = GlobalConfiguration.Configuration;
24+
Initialize(GlobalConfiguration.Configuration, "PackagesOData");
25+
}
2326

24-
NuGetV2WebApiEnabler.UseNuGetV2WebApiFeed(config, "NuGetDefault", "nuget", "PackagesOData");
27+
public static void Initialize(HttpConfiguration config, string controllerName)
28+
{
29+
NuGetV2WebApiEnabler.UseNuGetV2WebApiFeed(config, "NuGetDefault", "nuget", controllerName);
2530

2631
config.Routes.MapHttpRoute(
2732
name: "NuGetDefault_ClearCache",
2833
routeTemplate: "nuget/clear-cache",
29-
defaults: new { controller = "PackagesOData", action = "ClearCache" },
34+
defaults: new { controller = controllerName, action = nameof(PackagesODataController.ClearCache) },
3035
constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) }
3136
);
32-
3337
}
3438
}
3539
}

src/NuGet.Server/Controllers/PackagesODataController.cs

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,15 @@ namespace NuGet.Server.DataServices
1414
public class PackagesODataController : NuGetODataController
1515
{
1616
public PackagesODataController()
17-
: base(Repository, AuthenticationService)
17+
: this(ServiceResolver.Current)
1818
{
19-
_maxPageSize = 100;
2019
}
2120

22-
private static IServerPackageRepository Repository
21+
protected PackagesODataController(IServiceResolver serviceResolver)
22+
: base(serviceResolver.Resolve<IServerPackageRepository>(),
23+
serviceResolver.Resolve<IPackageAuthenticationService>())
2324
{
24-
get
25-
{
26-
// It's bad to use the container directly but we aren't in the loop when this
27-
// class is created
28-
return ServiceResolver.Resolve<IServerPackageRepository>();
29-
}
30-
}
31-
32-
private static IPackageAuthenticationService AuthenticationService
33-
{
34-
get
35-
{
36-
// It's bad to use the container directly but we aren't in the loop when this
37-
// class is created
38-
return ServiceResolver.Resolve<IPackageAuthenticationService>();
39-
}
25+
_maxPageSize = 100;
4026
}
4127

4228
[HttpGet]

src/NuGet.Server/Core/DefaultServiceResolver.cs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,38 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
2-
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
34
using System;
5+
using System.Collections.Specialized;
6+
using System.Web.Configuration;
47
using NuGet.Server.Core.Infrastructure;
58
using NuGet.Server.Core.Logging;
69
using NuGet.Server.Infrastructure;
710

811
namespace NuGet.Server
912
{
10-
public class DefaultServiceResolver
11-
: IServiceResolver
13+
public sealed class DefaultServiceResolver
14+
: IServiceResolver, IDisposable
1215
{
13-
private readonly IHashProvider _hashProvider;
14-
private readonly IServerPackageRepository _packageRepository;
15-
private readonly IPackageAuthenticationService _packageAuthenticationService;
16-
private readonly ISettingsProvider _settingsProvider;
16+
private readonly CryptoHashProvider _hashProvider;
17+
private readonly ServerPackageRepository _packageRepository;
18+
private readonly PackageAuthenticationService _packageAuthenticationService;
19+
private readonly WebConfigSettingsProvider _settingsProvider;
20+
21+
public DefaultServiceResolver() : this(
22+
PackageUtility.PackagePhysicalPath,
23+
WebConfigurationManager.AppSettings)
24+
{
25+
}
1726

18-
public DefaultServiceResolver()
27+
public DefaultServiceResolver(string packagePath, NameValueCollection settings)
1928
{
2029
_hashProvider = new CryptoHashProvider(Core.Constants.HashAlgorithm);
2130

22-
_settingsProvider = new WebConfigSettingsProvider();
31+
_settingsProvider = new WebConfigSettingsProvider(settings);
2332

24-
_packageRepository = new ServerPackageRepository(PackageUtility.PackagePhysicalPath, _hashProvider, _settingsProvider, new TraceLogger());
33+
_packageRepository = new ServerPackageRepository(packagePath, _hashProvider, _settingsProvider, new TraceLogger());
2534

26-
_packageAuthenticationService = new PackageAuthenticationService();
35+
_packageAuthenticationService = new PackageAuthenticationService(settings);
2736

2837
}
2938

@@ -44,8 +53,12 @@ public object Resolve(Type type)
4453
return _packageAuthenticationService;
4554
}
4655

47-
4856
return null;
4957
}
58+
59+
public void Dispose()
60+
{
61+
_packageRepository.Dispose();
62+
}
5063
}
5164
}

src/NuGet.Server/Core/ServiceResolver.cs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,5 @@ public static void SetServiceResolver(IServiceResolver serviceResolver)
2626
{
2727
Current = serviceResolver;
2828
}
29-
30-
public static T Resolve<T>()
31-
where T : class
32-
{
33-
EnsureServiceResolver();
34-
35-
return Current.Resolve(typeof (T)) as T;
36-
}
3729
}
3830
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
namespace NuGet.Server
5+
{
6+
public static class ServiceResolverExtensions
7+
{
8+
public static T Resolve<T>(this IServiceResolver resolver)
9+
where T : class
10+
{
11+
return resolver.Resolve(typeof(T)) as T;
12+
}
13+
}
14+
}

src/NuGet.Server/Infrastructure/PackageAuthenticationService.cs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
2-
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
34
using System;
45
using System.Collections.Specialized;
56
using System.Security.Principal;
@@ -10,16 +11,24 @@ namespace NuGet.Server.Infrastructure
1011
{
1112
public class PackageAuthenticationService : IPackageAuthenticationService
1213
{
13-
public bool IsAuthenticated(IPrincipal user, string apiKey, string packageId)
14+
private readonly Func<NameValueCollection> _getSettings;
15+
16+
public PackageAuthenticationService()
17+
{
18+
_getSettings = () => WebConfigurationManager.AppSettings;
19+
}
20+
21+
public PackageAuthenticationService(NameValueCollection settings)
1422
{
15-
var appSettings = WebConfigurationManager.AppSettings;
16-
return IsAuthenticatedInternal(apiKey, appSettings);
23+
_getSettings = () => settings;
1724
}
1825

19-
internal static bool IsAuthenticatedInternal(string apiKey, NameValueCollection appSettings)
26+
public bool IsAuthenticated(IPrincipal user, string apiKey, string packageId)
2027
{
28+
var settings = _getSettings();
29+
2130
bool value;
22-
if (!Boolean.TryParse(appSettings["requireApiKey"], out value))
31+
if (!bool.TryParse(settings["requireApiKey"], out value))
2332
{
2433
// If the setting is misconfigured, fail.
2534
return false;
@@ -31,10 +40,10 @@ internal static bool IsAuthenticatedInternal(string apiKey, NameValueCollection
3140
return true;
3241
}
3342

34-
var settingsApiKey = appSettings["apiKey"];
43+
var settingsApiKey = settings["apiKey"];
3544

3645
// No api key, no-one can push
37-
if (String.IsNullOrEmpty(settingsApiKey))
46+
if (string.IsNullOrEmpty(settingsApiKey))
3847
{
3948
return false;
4049
}
Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,32 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
2-
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
34
using System;
5+
using System.Collections.Specialized;
46
using System.Web.Configuration;
57
using NuGet.Server.Core.Infrastructure;
68

79
namespace NuGet.Server.Infrastructure
810
{
911
public class WebConfigSettingsProvider : ISettingsProvider
1012
{
13+
private readonly Func<NameValueCollection> _getSettings;
14+
15+
public WebConfigSettingsProvider()
16+
{
17+
_getSettings = () => WebConfigurationManager.AppSettings;
18+
}
19+
20+
public WebConfigSettingsProvider(NameValueCollection settings)
21+
{
22+
_getSettings = () => settings;
23+
}
24+
1125
public bool GetBoolSetting(string key, bool defaultValue)
1226
{
13-
var appSettings = WebConfigurationManager.AppSettings;
27+
var settings = _getSettings();
1428
bool value;
15-
return !Boolean.TryParse(appSettings[key], out value) ? defaultValue : value;
29+
return !bool.TryParse(settings[key], out value) ? defaultValue : value;
1630
}
1731
}
1832
}

src/NuGet.Server/NuGet.Server.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108
<Compile Include="Core\IServiceResolver.cs" />
109109
<Compile Include="Core\ServiceResolver.cs" />
110110
<Compile Include="Controllers\PackagesODataController.cs" />
111+
<Compile Include="Core\ServiceResolverExtensions.cs" />
111112
<Compile Include="Infrastructure\WebConfigSettingsProvider.cs" />
112113
<Compile Include="Core\Helpers.cs" />
113114
<Compile Include="Infrastructure\PackageAuthenticationService.cs" />

0 commit comments

Comments
 (0)