Skip to content

Commit f507bd2

Browse files
committedFeb 5, 2018
Merge branch 'dev' into master
2 parents c7d9144 + 44ce576 commit f507bd2

18 files changed

+465
-24
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
using System;
34
using System.Collections.Generic;
45
using NuGet.Server.Core.Infrastructure;
56

67
namespace NuGet.Server.V2.Samples.OwinHost
78
{
89
public class DictionarySettingsProvider : ISettingsProvider
910
{
10-
readonly Dictionary<string, bool> _settings;
11+
readonly Dictionary<string, object> _settings;
1112

12-
public DictionarySettingsProvider(Dictionary<string, bool> settings)
13+
public DictionarySettingsProvider(Dictionary<string, object> settings)
1314
{
1415
_settings = settings;
1516
}
@@ -18,8 +19,13 @@ public DictionarySettingsProvider(Dictionary<string, bool> settings)
1819
public bool GetBoolSetting(string key, bool defaultValue)
1920
{
2021
System.Diagnostics.Debug.WriteLine("getSetting: " + key);
21-
return _settings.ContainsKey(key) ? _settings[key] : defaultValue;
22+
return _settings.ContainsKey(key) ? Convert.ToBoolean(_settings[key]) : defaultValue;
2223

2324
}
25+
26+
public string GetStringSetting(string key, string defaultValue)
27+
{
28+
return _settings.ContainsKey(key) ? Convert.ToString(_settings[key]) : defaultValue;
29+
}
2430
}
2531
}

‎samples/NuGet.Server.V2.Samples.OwinHost/Program.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ static void Main(string[] args)
2424

2525
// Set up a common settingsProvider to be used by all repositories.
2626
// If a setting is not present in dictionary default value will be used.
27-
var settings = new Dictionary<string, bool>();
27+
var settings = new Dictionary<string, object>();
2828
settings.Add("enableDelisting", false); //default=false
2929
settings.Add("enableFrameworkFiltering", false); //default=false
3030
settings.Add("ignoreSymbolsPackages", true); //default=false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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+
using System;
5+
using System.Collections.Generic;
6+
using System.IO;
7+
8+
namespace NuGet.Server.Core
9+
{
10+
/// <summary>
11+
/// A file system implementation that persists nothing. This is intended to be used with
12+
/// <see cref="OptimizedZipPackage"/> so that package files are never actually extracted anywhere on disk.
13+
/// </summary>
14+
public class NullFileSystem : IFileSystem
15+
{
16+
public static NullFileSystem Instance { get; } = new NullFileSystem();
17+
18+
public Stream CreateFile(string path) => Stream.Null;
19+
public bool DirectoryExists(string path) => true;
20+
public bool FileExists(string path) => false;
21+
public string GetFullPath(string path) => null;
22+
public Stream OpenFile(string path) => Stream.Null;
23+
24+
public ILogger Logger { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
25+
public string Root => throw new NotSupportedException();
26+
public void AddFile(string path, Stream stream) => throw new NotSupportedException();
27+
public void AddFile(string path, Action<Stream> writeToStream) => throw new NotSupportedException();
28+
public void AddFiles(IEnumerable<IPackageFile> files, string rootDir) => throw new NotSupportedException();
29+
public void DeleteDirectory(string path, bool recursive) => throw new NotSupportedException();
30+
public void DeleteFile(string path) => throw new NotSupportedException();
31+
public void DeleteFiles(IEnumerable<IPackageFile> files, string rootDir) => throw new NotSupportedException();
32+
public DateTimeOffset GetCreated(string path) => throw new NotSupportedException();
33+
public IEnumerable<string> GetDirectories(string path) => throw new NotSupportedException();
34+
public IEnumerable<string> GetFiles(string path, string filter, bool recursive) => throw new NotSupportedException();
35+
public DateTimeOffset GetLastAccessed(string path) => throw new NotSupportedException();
36+
public DateTimeOffset GetLastModified(string path) => throw new NotSupportedException();
37+
public void MakeFileWritable(string path) => throw new NotSupportedException();
38+
public void MoveFile(string source, string destination) => throw new NotSupportedException();
39+
}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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+
using System;
5+
using System.IO;
6+
7+
namespace NuGet.Server.Core
8+
{
9+
public static class PackageFactory
10+
{
11+
public static IPackage Open(string fullPackagePath)
12+
{
13+
if (string.IsNullOrEmpty(fullPackagePath))
14+
{
15+
throw new ArgumentNullException(nameof(fullPackagePath));
16+
}
17+
18+
var directoryName = Path.GetDirectoryName(fullPackagePath);
19+
var fileName = Path.GetFileName(fullPackagePath);
20+
21+
var fileSystem = new PhysicalFileSystem(directoryName);
22+
23+
return new OptimizedZipPackage(
24+
fileSystem,
25+
fileName,
26+
NullFileSystem.Instance);
27+
}
28+
}
29+
}

‎src/NuGet.Server.Core/Infrastructure/DefaultSettingsProvider.cs

+5
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,10 @@ public bool GetBoolSetting(string key, bool defaultValue)
88
{
99
return defaultValue;
1010
}
11+
12+
public string GetStringSetting(string key, string defaultValue)
13+
{
14+
return defaultValue;
15+
}
1116
}
1217
}

‎src/NuGet.Server.Core/Infrastructure/ISettingsProvider.cs

+1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ namespace NuGet.Server.Core.Infrastructure
55
public interface ISettingsProvider
66
{
77
bool GetBoolSetting(string key, bool defaultValue);
8+
string GetStringSetting(string key, string defaultValue);
89
}
910
}

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

+35-5
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public ServerPackageRepository(
5858
_runBackgroundTasks = true;
5959
_settingsProvider = settingsProvider ?? new DefaultSettingsProvider();
6060
_logger = logger ?? new TraceLogger();
61-
_serverPackageCache = InitializeServerPackageStore();
61+
_serverPackageCache = InitializeServerPackageCache();
6262
_serverPackageStore = new ServerPackageStore(
6363
_fileSystem,
6464
new ExpandedPackageRepository(_fileSystem, hashProvider),
@@ -81,7 +81,7 @@ internal ServerPackageRepository(
8181
_runBackgroundTasks = runBackgroundTasks;
8282
_settingsProvider = settingsProvider ?? new DefaultSettingsProvider();
8383
_logger = logger ?? new TraceLogger();
84-
_serverPackageCache = InitializeServerPackageStore();
84+
_serverPackageCache = InitializeServerPackageCache();
8585
_serverPackageStore = new ServerPackageStore(
8686
_fileSystem,
8787
innerRepository,
@@ -105,9 +105,39 @@ internal ServerPackageRepository(
105105
private bool EnableFileSystemMonitoring =>
106106
_settingsProvider.GetBoolSetting("enableFileSystemMonitoring", true);
107107

108-
private ServerPackageCache InitializeServerPackageStore()
108+
private string CacheFileName => _settingsProvider.GetStringSetting("cacheFileName", null);
109+
110+
private ServerPackageCache InitializeServerPackageCache()
109111
{
110-
return new ServerPackageCache(_fileSystem, Environment.MachineName.ToLowerInvariant() + ".cache.bin");
112+
return new ServerPackageCache(_fileSystem, ResolveCacheFileName());
113+
}
114+
115+
private string ResolveCacheFileName()
116+
{
117+
var fileName = CacheFileName;
118+
const string suffix = ".cache.bin";
119+
120+
if (String.IsNullOrWhiteSpace(fileName))
121+
{
122+
// Default file name
123+
return Environment.MachineName.ToLowerInvariant() + suffix;
124+
}
125+
126+
if (fileName.LastIndexOfAny(Path.GetInvalidFileNameChars()) > 0)
127+
{
128+
var message = string.Format(Strings.Error_InvalidCacheFileName, fileName);
129+
130+
_logger.Log(LogLevel.Error, message);
131+
132+
throw new InvalidOperationException(message);
133+
}
134+
135+
if (fileName.EndsWith(suffix, StringComparison.OrdinalIgnoreCase))
136+
{
137+
return fileName;
138+
}
139+
140+
return fileName + suffix;
111141
}
112142

113143
/// <summary>
@@ -236,7 +266,7 @@ private void AddPackagesFromDropFolderWithoutLocking()
236266
try
237267
{
238268
// Create package
239-
var package = new OptimizedZipPackage(_fileSystem, packageFile);
269+
var package = PackageFactory.Open(_fileSystem.GetFullPath(packageFile));
240270

241271
if (!CanPackageBeAddedWithoutLocking(package, shouldThrow: false))
242272
{

‎src/NuGet.Server.Core/NuGet.Server.Core.csproj

+2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@
5858
</Compile>
5959
<Compile Include="Core\Constants.cs" />
6060
<Compile Include="Core\FrameworkNameExtensions.cs" />
61+
<Compile Include="Core\NullFileSystem.cs" />
6162
<Compile Include="Core\PackageExtensions.cs" />
63+
<Compile Include="Core\PackageFactory.cs" />
6264
<Compile Include="DataServices\IgnoreCaseForPackageIdInterceptor.cs" />
6365
<Compile Include="DataServices\NormalizeVersionInterceptor.cs" />
6466
<Compile Include="DataServices\ODataPackage.cs" />

‎src/NuGet.Server.Core/Strings.Designer.cs

+9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎src/NuGet.Server.Core/Strings.resx

+3
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@
117117
<resheader name="writer">
118118
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
119119
</resheader>
120+
<data name="Error_InvalidCacheFileName" xml:space="preserve">
121+
<value>Configured cache file name '{0}' is invalid. Keep it simple; No paths allowed.</value>
122+
</data>
120123
<data name="Error_PackageAlreadyExists" xml:space="preserve">
121124
<value>Package {0} already exists. The server is configured to not allow overwriting packages that already exist.</value>
122125
</data>

‎src/NuGet.Server.V2/Controllers/NuGetODataController.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using System.Web.Http;
1515
using System.Web.Http.OData;
1616
using System.Web.Http.OData.Query;
17+
using NuGet.Server.Core;
1718
using NuGet.Server.Core.DataServices;
1819
using NuGet.Server.Core.Infrastructure;
1920
using NuGet.Server.V2.Model;
@@ -396,8 +397,7 @@ public virtual async Task<HttpResponseMessage> UploadPackage(CancellationToken t
396397
}
397398
}
398399

399-
var package = new OptimizedZipPackage(temporaryFile);
400-
400+
var package = PackageFactory.Open(temporaryFile);
401401

402402
HttpResponseMessage retValue;
403403
if (_authenticationService.IsAuthenticated(User, apiKey, package.Id))

‎src/NuGet.Server/Infrastructure/WebConfigSettingsProvider.cs

+6
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,11 @@ public bool GetBoolSetting(string key, bool defaultValue)
2828
bool value;
2929
return !bool.TryParse(settings[key], out value) ? defaultValue : value;
3030
}
31+
32+
public string GetStringSetting(string key, string defaultValue)
33+
{
34+
var settings = _getSettings();
35+
return settings[key] ?? defaultValue;
36+
}
3137
}
3238
}

‎src/NuGet.Server/Web.config

+6
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@
2222
-->
2323
<add key="packagesPath" value="" />
2424

25+
<!--
26+
Change the name of the internal cache file. Default is machine name (System.Environment.MachineName).
27+
This is the name of the cache file in the packages folder. No paths allowed.
28+
-->
29+
<add key="cacheFileName" value="" />
30+
2531
<!--
2632
Set allowOverrideExistingPackageOnPush to false to mimic NuGet.org's behaviour (do not allow overwriting packages with same id + version).
2733
-->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
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+
using System;
5+
using System.IO;
6+
using NuGet.Server.Core.Tests.Infrastructure;
7+
using Xunit;
8+
9+
namespace NuGet.Server.Core.Tests.Core
10+
{
11+
public class PackageFactoryTest
12+
{
13+
public class Open : IDisposable
14+
{
15+
private readonly TemporaryDirectory _directory;
16+
17+
public Open()
18+
{
19+
_directory = new TemporaryDirectory();
20+
}
21+
22+
[Theory]
23+
[InlineData(null)]
24+
[InlineData("")]
25+
public void RejectsInvalidPaths(string path)
26+
{
27+
var ex = Assert.Throws<ArgumentNullException>(
28+
() => PackageFactory.Open(path));
29+
Assert.Equal("fullPackagePath", ex.ParamName);
30+
}
31+
32+
[Fact]
33+
public void InitializesPackageWithMetadata()
34+
{
35+
// Arrange
36+
var path = Path.Combine(_directory, "package.nupkg");
37+
TestData.CopyResourceToPath(TestData.PackageResource, path);
38+
39+
// Act
40+
var package = PackageFactory.Open(path);
41+
42+
// Assert
43+
Assert.Equal(TestData.PackageId, package.Id);
44+
Assert.Equal(TestData.PackageVersion, package.Version);
45+
}
46+
47+
[Fact]
48+
public void InitializesPackageWithSupportedFrameworks()
49+
{
50+
// Arrange
51+
var path = Path.Combine(_directory, "package.nupkg");
52+
TestData.CopyResourceToPath(TestData.PackageResource, path);
53+
54+
// Act
55+
var package = PackageFactory.Open(path);
56+
57+
// Assert
58+
var frameworks = package.GetSupportedFrameworks();
59+
var framework = Assert.Single(frameworks);
60+
Assert.Equal(VersionUtility.ParseFrameworkName("net40-client"), framework);
61+
}
62+
63+
[Fact]
64+
public void InitializesPackageWhichCanBeCheckedForSymbols()
65+
{
66+
// Arrange
67+
var path = Path.Combine(_directory, "package.nupkg");
68+
TestData.CopyResourceToPath(TestData.PackageResource, path);
69+
70+
// Act
71+
var package = PackageFactory.Open(path);
72+
73+
// Assert
74+
Assert.False(package.IsSymbolsPackage(), "The provided package is not a symbols package.");
75+
}
76+
77+
public void Dispose()
78+
{
79+
_directory?.Dispose();
80+
}
81+
}
82+
}
83+
}

‎test/NuGet.Server.Core.Tests/Infrastructure/FuncSettingsProvider.cs

+8-3
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ namespace NuGet.Server.Core.Tests.Infrastructure
77
{
88
class FuncSettingsProvider : ISettingsProvider
99
{
10-
readonly Func<string, bool, bool> _getSetting;
11-
internal FuncSettingsProvider(Func<string,bool,bool> getSetting)
10+
readonly Func<string, object, object> _getSetting;
11+
internal FuncSettingsProvider(Func<string, object, object> getSetting)
1212
{
1313
if (getSetting == null)
1414
{
@@ -20,7 +20,12 @@ internal FuncSettingsProvider(Func<string,bool,bool> getSetting)
2020

2121
public bool GetBoolSetting(string key, bool defaultValue)
2222
{
23-
return _getSetting(key, defaultValue);
23+
return Convert.ToBoolean(_getSetting(key, defaultValue));
24+
}
25+
26+
public string GetStringSetting(string key, string defaultValue)
27+
{
28+
return Convert.ToString(_getSetting(key, defaultValue));
2429
}
2530
}
2631
}

‎test/NuGet.Server.Core.Tests/NuGet.Server.Core.Tests.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
<ItemGroup>
8282
<Compile Include="ApiKeyPackageAuthenticationServiceTest.cs" />
8383
<Compile Include="ClientCompatibilityFactoryTests.cs" />
84+
<Compile Include="Core\PackageFactoryTest.cs" />
8485
<Compile Include="IdAndVersionEqualityComparerTest.cs" />
8586
<Compile Include="IgnoreCaseForPackageIdInterceptorTest.cs" />
8687
<Compile Include="Infrastructure\FuncSettingsProvider.cs" />

‎test/NuGet.Server.Core.Tests/ServerPackageRepositoryTest.cs

+83-6
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public class ServerPackageRepositoryTest
2323
public static async Task<ServerPackageRepository> CreateServerPackageRepositoryAsync(
2424
string path,
2525
Action<ExpandedPackageRepository> setupRepository = null,
26-
Func<string, bool, bool> getSetting = null)
26+
Func<string, object, object> getSetting = null)
2727
{
2828
var fileSystem = new PhysicalFileSystem(path);
2929
var expandedPackageRepository = new ExpandedPackageRepository(fileSystem);
@@ -514,7 +514,7 @@ public async Task ServerPackageRepositorySemVer1IsAbsoluteLatest(bool enableDeli
514514
using (var temporaryDirectory = new TemporaryDirectory())
515515
{
516516
// Arrange
517-
var getSetting = enableDelisting ? EnableDelisting : (Func<string, bool, bool>)null;
517+
var getSetting = enableDelisting ? EnableDelisting : (Func<string, object, object>)null;
518518
var serverRepository = await CreateServerPackageRepositoryAsync(temporaryDirectory.Path, repository =>
519519
{
520520
repository.AddPackage(CreatePackage("test", "2.0-alpha"));
@@ -548,7 +548,7 @@ public async Task ServerPackageRepositorySemVer2IsAbsoluteLatest(bool enableDeli
548548
using (var temporaryDirectory = new TemporaryDirectory())
549549
{
550550
// Arrange
551-
var getSetting = enableDelisting ? EnableDelisting : (Func<string, bool, bool>)null;
551+
var getSetting = enableDelisting ? EnableDelisting : (Func<string, object, object>)null;
552552
var serverRepository = await CreateServerPackageRepositoryAsync(temporaryDirectory.Path, repository =>
553553
{
554554
repository.AddPackage(CreatePackage("test", "2.0-alpha"));
@@ -603,7 +603,7 @@ public async Task ServerPackageRepositorySemVer1IsLatest(bool enableDelisting)
603603
using (var temporaryDirectory = new TemporaryDirectory())
604604
{
605605
// Arrange
606-
var getSetting = enableDelisting ? EnableDelisting : (Func<string, bool, bool>)null;
606+
var getSetting = enableDelisting ? EnableDelisting : (Func<string, object, object>)null;
607607
var serverRepository = await CreateServerPackageRepositoryAsync(temporaryDirectory.Path, repository =>
608608
{
609609
repository.AddPackage(CreatePackage("test1", "1.0.0"));
@@ -634,7 +634,7 @@ public async Task ServerPackageRepositorySemVer2IsLatest(bool enableDelisting)
634634
using (var temporaryDirectory = new TemporaryDirectory())
635635
{
636636
// Arrange
637-
var getSetting = enableDelisting ? EnableDelisting : (Func<string, bool, bool>)null;
637+
var getSetting = enableDelisting ? EnableDelisting : (Func<string, object, object>)null;
638638
var serverRepository = await CreateServerPackageRepositoryAsync(temporaryDirectory.Path, repository =>
639639
{
640640
repository.AddPackage(CreatePackage("test", "1.11"));
@@ -811,6 +811,83 @@ public async Task ServerPackageRepositoryAddPackageRejectsDuplicatesWithSemVer2(
811811
}
812812
}
813813

814+
[Theory]
815+
[InlineData(null)]
816+
[InlineData("")]
817+
[InlineData(" ")]
818+
public async Task ServerPackageRepository_CustomCacheFileNameNotConfigured_UseMachineNameAsFileName(string fileNameFromConfig)
819+
{
820+
using (var temporaryDirectory = new TemporaryDirectory())
821+
{
822+
ServerPackageRepository serverRepository = await CreateServerPackageRepositoryAsync(
823+
temporaryDirectory.Path,
824+
getSetting: (key, defaultValue) => key == "cacheFileName" ? fileNameFromConfig : defaultValue);
825+
826+
string expectedCacheFileName = Path.Combine(serverRepository.Source, Environment.MachineName.ToLowerInvariant() + ".cache.bin");
827+
828+
Assert.True(File.Exists(expectedCacheFileName));
829+
}
830+
}
831+
832+
[Fact]
833+
public async Task ServerPackageRepository_CustomCacheFileNameIsConfigured_CustomCacheFileIsCreated()
834+
{
835+
using (var temporaryDirectory = new TemporaryDirectory())
836+
{
837+
ServerPackageRepository serverRepository = await CreateServerPackageRepositoryAsync(
838+
temporaryDirectory.Path,
839+
getSetting: (key, defaultValue) => key == "cacheFileName" ? "CustomFileName.cache.bin" : defaultValue);
840+
841+
string expectedCacheFileName = Path.Combine(serverRepository.Source, "CustomFileName.cache.bin");
842+
843+
Assert.True(File.Exists(expectedCacheFileName));
844+
}
845+
}
846+
847+
[Fact]
848+
public async Task ServerPackageRepository_CustomCacheFileNameWithoutExtensionIsConfigured_CustomCacheFileWithExtensionIsCreated()
849+
{
850+
using (var temporaryDirectory = new TemporaryDirectory())
851+
{
852+
ServerPackageRepository serverRepository = await CreateServerPackageRepositoryAsync(
853+
temporaryDirectory.Path,
854+
getSetting: (key, defaultValue) => key == "cacheFileName" ? "CustomFileName" : defaultValue);
855+
856+
string expectedCacheFileName = Path.Combine(serverRepository.Source, "CustomFileName.cache.bin");
857+
858+
Assert.True(File.Exists(expectedCacheFileName));
859+
}
860+
}
861+
862+
[Theory]
863+
[InlineData("c:\\file\\is\\a\\path\\to\\Awesome.cache.bin")]
864+
[InlineData("random:invalidFileName.cache.bin")]
865+
public async Task ServerPackageRepository_CustomCacheFileNameIsInvalid_ThrowUp(string invlaidCacheFileName)
866+
{
867+
using (var temporaryDirectory = new TemporaryDirectory())
868+
{
869+
Task Code() => CreateServerPackageRepositoryAsync(
870+
temporaryDirectory.Path,
871+
getSetting: (key, defaultValue) => key == "cacheFileName" ? invlaidCacheFileName : defaultValue);
872+
873+
await Assert.ThrowsAsync<InvalidOperationException>(Code);
874+
}
875+
}
876+
877+
[Fact]
878+
public async Task ServerPackageRepository_CustomCacheFileNameIsInvalid_ThrowUpWithCorrectErrorMessage()
879+
{
880+
using (var temporaryDirectory = new TemporaryDirectory())
881+
{
882+
Task Code() => CreateServerPackageRepositoryAsync(
883+
temporaryDirectory.Path,
884+
getSetting: (key, defaultValue) => key == "cacheFileName" ? "foo:bar/baz" : defaultValue);
885+
886+
var expectedMessage = "Configured cache file name 'foo:bar/baz' is invalid. Keep it simple; No paths allowed.";
887+
Assert.Equal(expectedMessage, (await Assert.ThrowsAsync<InvalidOperationException>(Code)).Message);
888+
}
889+
}
890+
814891
private static IPackage CreateMockPackage(string id, string version)
815892
{
816893
var package = new Mock<IPackage>();
@@ -879,7 +956,7 @@ private IPackage CreatePackage(
879956
return outputPackage;
880957
}
881958

882-
private static bool EnableDelisting(string key, bool defaultValue)
959+
private static object EnableDelisting(string key, object defaultValue)
883960
{
884961
if (key == "enableDelisting")
885962
{

‎test/NuGet.Server.Tests/IntegrationTests.cs

+142-4
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@
66
using System.Collections.Generic;
77
using System.Collections.Specialized;
88
using System.IO;
9+
using System.Linq;
910
using System.Net;
1011
using System.Net.Http;
1112
using System.Net.Http.Headers;
13+
using System.Threading;
1214
using System.Threading.Tasks;
1315
using System.Web.Http;
1416
using System.Web.Http.Dependencies;
1517
using NuGet.Server.App_Start;
18+
using NuGet.Server.Core.Infrastructure;
1619
using NuGet.Server.Core.Tests;
1720
using NuGet.Server.Core.Tests.Infrastructure;
1821
using Xunit;
@@ -56,6 +59,72 @@ public async Task DropPackageThenReadPackages()
5659
}
5760
}
5861

62+
[Fact]
63+
public async Task DownloadPackage()
64+
{
65+
// Arrange
66+
using (var tc = new TestContext())
67+
{
68+
// Act & Assert
69+
// 1. Write a package to the drop folder.
70+
var packagePath = Path.Combine(tc.PackagesDirectory, "package.nupkg");
71+
TestData.CopyResourceToPath(TestData.PackageResource, packagePath);
72+
var expectedBytes = File.ReadAllBytes(packagePath);
73+
74+
// 2. Download the package.
75+
using (var request = new HttpRequestMessage(
76+
HttpMethod.Get,
77+
$"/nuget/Packages(Id='{TestData.PackageId}',Version='{TestData.PackageVersionString}')/Download"))
78+
using (var response = await tc.Client.SendAsync(request))
79+
{
80+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
81+
var actualBytes = await response.Content.ReadAsByteArrayAsync();
82+
83+
Assert.Equal("binary/octet-stream", response.Content.Headers.ContentType.ToString());
84+
Assert.Equal(expectedBytes, actualBytes);
85+
}
86+
}
87+
}
88+
89+
[Fact]
90+
public async Task FilterOnFramework()
91+
{
92+
// Arrange
93+
using (var tc = new TestContext())
94+
{
95+
tc.Settings["enableFrameworkFiltering"] = "true";
96+
97+
// Act & Assert
98+
// 1. Write a package to the drop folder.
99+
var packagePath = Path.Combine(tc.PackagesDirectory, "package.nupkg");
100+
TestData.CopyResourceToPath(TestData.PackageResource, packagePath);
101+
102+
// 2. Search for all packages supporting .NET Framework 4.6 (this should match the test package)
103+
using (var request = new HttpRequestMessage(
104+
HttpMethod.Get,
105+
$"/nuget/Search?targetFramework='net46'"))
106+
using (var response = await tc.Client.SendAsync(request))
107+
{
108+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
109+
var content = await response.Content.ReadAsStringAsync();
110+
111+
Assert.Contains(TestData.PackageId, content);
112+
}
113+
114+
// 3. Search for all packages supporting .NET Framework 2.0 (this should match nothing)
115+
using (var request = new HttpRequestMessage(
116+
HttpMethod.Get,
117+
$"/nuget/Search?targetFramework='net20'"))
118+
using (var response = await tc.Client.SendAsync(request))
119+
{
120+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
121+
var content = await response.Content.ReadAsStringAsync();
122+
123+
Assert.DoesNotContain(TestData.PackageId, content);
124+
}
125+
}
126+
}
127+
59128
[Fact]
60129
public async Task PushPackageThenReadPackages()
61130
{
@@ -122,6 +191,75 @@ public async Task CanQueryUsingProjection(string endpoint)
122191
}
123192
}
124193

194+
[Fact]
195+
public async Task DoesNotWriteToNuGetScratch()
196+
{
197+
// Arrange
198+
OptimizedZipPackage.PurgeCache();
199+
var expectedTempEntries = Directory
200+
.GetFileSystemEntries(Path.Combine(Path.GetTempPath(), "NuGetScratch"))
201+
.OrderBy(x => x)
202+
.ToList();
203+
204+
using (var tc = new TestContext())
205+
{
206+
tc.Settings["enableFrameworkFiltering"] = "true";
207+
tc.Settings["allowOverrideExistingPackageOnPush"] = "true";
208+
209+
string apiKey = "foobar";
210+
tc.SetApiKey(apiKey);
211+
212+
// Act & Assert
213+
// 1. Write a package to the drop folder.
214+
var packagePath = Path.Combine(tc.PackagesDirectory, "package.nupkg");
215+
TestData.CopyResourceToPath(TestData.PackageResource, packagePath);
216+
217+
// 2. Search for packages.
218+
using (var request = new HttpRequestMessage(
219+
HttpMethod.Get,
220+
$"/nuget/Search?targetFramework='net46'"))
221+
using (var response = await tc.Client.SendAsync(request))
222+
{
223+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
224+
}
225+
226+
// 3. Push the package.
227+
var pushPath = Path.Combine(tc.TemporaryDirectory, "package.nupkg");
228+
TestData.CopyResourceToPath(TestData.PackageResource, pushPath);
229+
using (var request = new HttpRequestMessage(HttpMethod.Put, "/nuget")
230+
{
231+
Headers =
232+
{
233+
{ "X-NUGET-APIKEY", apiKey }
234+
},
235+
Content = tc.GetFileUploadContent(pushPath),
236+
})
237+
{
238+
using (request)
239+
using (var response = await tc.Client.SendAsync(request))
240+
{
241+
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
242+
}
243+
}
244+
245+
// 4. Search for packages again.
246+
using (var request = new HttpRequestMessage(
247+
HttpMethod.Get,
248+
$"/nuget/Search?targetFramework='net46'"))
249+
using (var response = await tc.Client.SendAsync(request))
250+
{
251+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
252+
}
253+
254+
// 6. Make sure we have not added more temp files.
255+
var actualTempEntries = Directory
256+
.GetFileSystemEntries(Path.Combine(Path.GetTempPath(), "NuGetScratch"))
257+
.OrderBy(x => x)
258+
.ToList();
259+
Assert.Equal(expectedTempEntries, actualTempEntries);
260+
}
261+
}
262+
125263
public static IEnumerable<object[]> EndpointsSupportingProjection
126264
{
127265
get
@@ -135,7 +273,6 @@ public static IEnumerable<object[]> EndpointsSupportingProjection
135273
private sealed class TestContext : IDisposable
136274
{
137275
private readonly HttpServer _server;
138-
private readonly DefaultServiceResolver _serviceResolver;
139276
private readonly HttpConfiguration _config;
140277

141278
public TestContext()
@@ -149,11 +286,11 @@ public TestContext()
149286
{ "apiKey", string.Empty }
150287
};
151288

152-
_serviceResolver = new DefaultServiceResolver(PackagesDirectory, Settings);
289+
ServiceResolver = new DefaultServiceResolver(PackagesDirectory, Settings);
153290

154291
_config = new HttpConfiguration();
155292
_config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
156-
_config.DependencyResolver = new DependencyResolverAdapter(_serviceResolver);
293+
_config.DependencyResolver = new DependencyResolverAdapter(ServiceResolver);
157294

158295
NuGetODataConfig.Initialize(_config, "TestablePackagesOData");
159296

@@ -162,6 +299,7 @@ public TestContext()
162299
Client.BaseAddress = new Uri("http://localhost/");
163300
}
164301

302+
public DefaultServiceResolver ServiceResolver { get; }
165303
public TemporaryDirectory TemporaryDirectory { get; }
166304
public TemporaryDirectory PackagesDirectory { get; }
167305
public NameValueCollection Settings { get; }
@@ -198,7 +336,7 @@ public void Dispose()
198336
Client.Dispose();
199337
_server.Dispose();
200338
_config.Dispose();
201-
_serviceResolver.Dispose();
339+
ServiceResolver.Dispose();
202340
PackagesDirectory.Dispose();
203341
TemporaryDirectory.Dispose();
204342
}

0 commit comments

Comments
 (0)
Please sign in to comment.