2021-08-15 05:31:38 +01:00
|
|
|
using System;
|
2026-07-05 18:16:52 +01:00
|
|
|
using System.Collections.Generic;
|
2021-09-08 01:55:00 +01:00
|
|
|
using System.IO;
|
2026-07-05 18:16:52 +01:00
|
|
|
using System.Linq;
|
|
|
|
|
using System.Net;
|
2022-04-11 01:48:43 +01:00
|
|
|
using System.Net.Http;
|
2026-07-05 18:16:52 +01:00
|
|
|
using System.Net.Sockets;
|
|
|
|
|
using System.Text;
|
2022-04-11 01:48:43 +01:00
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using Newtonsoft.Json;
|
2022-04-11 19:57:30 +01:00
|
|
|
using Xunit;
|
2022-07-10 17:05:05 +01:00
|
|
|
using isnd.Entities;
|
2026-07-05 18:16:52 +01:00
|
|
|
using Isn.Abstract;
|
2021-08-15 05:31:38 +01:00
|
|
|
|
2026-07-05 17:22:57 +01:00
|
|
|
namespace Isn.tests
|
2021-08-15 05:31:38 +01:00
|
|
|
{
|
2026-07-05 18:16:52 +01:00
|
|
|
public sealed class LocalSourceFixture : IDisposable
|
|
|
|
|
{
|
|
|
|
|
private readonly HttpListener listener;
|
|
|
|
|
private readonly Task listenerTask;
|
2026-07-05 21:18:37 +01:00
|
|
|
private readonly string configDirectory;
|
|
|
|
|
private readonly string originalConfigDirectory;
|
2026-07-05 18:16:52 +01:00
|
|
|
|
2026-07-05 21:44:49 +01:00
|
|
|
public string LastApiKeyHeader { get; private set; }
|
|
|
|
|
|
2026-07-05 18:16:52 +01:00
|
|
|
public LocalSourceFixture()
|
|
|
|
|
{
|
|
|
|
|
var port = GetFreePort();
|
2026-07-05 20:17:12 +01:00
|
|
|
var prefix = $"http://127.0.0.1:{port}/"+Constants.APIPrefix;
|
2026-07-05 18:16:52 +01:00
|
|
|
listener = new HttpListener();
|
|
|
|
|
listener.Prefixes.Add(prefix);
|
|
|
|
|
listener.Start();
|
|
|
|
|
|
|
|
|
|
listenerTask = Task.Run(async () =>
|
|
|
|
|
{
|
|
|
|
|
while (listener.IsListening)
|
|
|
|
|
{
|
|
|
|
|
HttpListenerContext context;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
context = await listener.GetContextAsync();
|
|
|
|
|
}
|
|
|
|
|
catch (HttpListenerException)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
catch (ObjectDisposedException)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-05 21:44:49 +01:00
|
|
|
if (context.Request.HttpMethod == "PUT")
|
|
|
|
|
{
|
|
|
|
|
LastApiKeyHeader = context.Request.Headers["X-NuGet-ApiKey"];
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-05 18:16:52 +01:00
|
|
|
var indexJson = JsonConvert.SerializeObject(new ApiIndexViewModel(prefix + "index.json")
|
|
|
|
|
{
|
|
|
|
|
Version = "3.0.0",
|
|
|
|
|
Resources = new[]
|
|
|
|
|
{
|
|
|
|
|
new Resource(prefix + "put", "PackagePublish/2.0.0")
|
|
|
|
|
{
|
|
|
|
|
Comment = "test publish endpoint"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
var payload = Encoding.UTF8.GetBytes(indexJson);
|
|
|
|
|
context.Response.ContentType = "application/json";
|
|
|
|
|
context.Response.ContentLength64 = payload.Length;
|
|
|
|
|
await context.Response.OutputStream.WriteAsync(payload, 0, payload.Length);
|
|
|
|
|
context.Response.Close();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2026-07-05 21:18:37 +01:00
|
|
|
configDirectory = Path.Combine(Path.GetTempPath(), $"isn-tests-{Guid.NewGuid():N}");
|
|
|
|
|
Directory.CreateDirectory(configDirectory);
|
|
|
|
|
originalConfigDirectory = Environment.GetEnvironmentVariable("ISN_CONFIG_DIR");
|
|
|
|
|
Environment.SetEnvironmentVariable("ISN_CONFIG_DIR", configDirectory);
|
|
|
|
|
|
2026-07-05 18:16:52 +01:00
|
|
|
SourceUrl = prefix + "index.json";
|
|
|
|
|
ConfigureIsnSettings(SourceUrl);
|
|
|
|
|
Program.LoadConfig();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string SourceUrl { get; }
|
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
listener.Close();
|
|
|
|
|
if (listenerTask != null)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
listenerTask.GetAwaiter().GetResult();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-07-05 21:18:37 +01:00
|
|
|
|
|
|
|
|
Environment.SetEnvironmentVariable("ISN_CONFIG_DIR", originalConfigDirectory);
|
|
|
|
|
if (Directory.Exists(configDirectory))
|
|
|
|
|
{
|
|
|
|
|
Directory.Delete(configDirectory, recursive: true);
|
|
|
|
|
}
|
2026-07-05 18:16:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static int GetFreePort()
|
|
|
|
|
{
|
|
|
|
|
var listener = new TcpListener(IPAddress.Loopback, 0);
|
|
|
|
|
listener.Start();
|
|
|
|
|
var port = ((IPEndPoint)listener.LocalEndpoint).Port;
|
|
|
|
|
listener.Stop();
|
|
|
|
|
return port;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-05 21:18:37 +01:00
|
|
|
private void ConfigureIsnSettings(string sourceUrl)
|
2026-07-05 18:16:52 +01:00
|
|
|
{
|
|
|
|
|
var configPath = Path.Combine(configDirectory, "config.json");
|
|
|
|
|
var settings = new Settings
|
|
|
|
|
{
|
|
|
|
|
DataProtectionTitle = "isn",
|
|
|
|
|
Sources = new Dictionary<string, SourceSettings>
|
|
|
|
|
{
|
|
|
|
|
[sourceUrl] = new SourceSettings { Alias = "test" }
|
|
|
|
|
},
|
|
|
|
|
DefaultSourceKey = sourceUrl
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
File.WriteAllText(configPath, JsonConvert.SerializeObject(settings, Formatting.Indented));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class Tests : IClassFixture<LocalSourceFixture>
|
2021-08-15 05:31:38 +01:00
|
|
|
{
|
2026-07-05 18:16:52 +01:00
|
|
|
private readonly LocalSourceFixture fixture;
|
|
|
|
|
|
|
|
|
|
public Tests(LocalSourceFixture fixture)
|
|
|
|
|
{
|
|
|
|
|
this.fixture = fixture;
|
|
|
|
|
}
|
2021-08-15 05:31:38 +01:00
|
|
|
|
2026-07-05 21:18:37 +01:00
|
|
|
[Fact]
|
|
|
|
|
public void SupportsIsolatedConfigDirectoryOverride()
|
|
|
|
|
{
|
|
|
|
|
var tempDir = Path.Combine(Path.GetTempPath(), $"isn-test-{Guid.NewGuid():N}");
|
|
|
|
|
Directory.CreateDirectory(tempDir);
|
|
|
|
|
var originalConfigDir = Environment.GetEnvironmentVariable("ISN_CONFIG_DIR");
|
|
|
|
|
var configFile = Path.Combine(tempDir, "config.json");
|
|
|
|
|
var expectedSource = "https://example.test/index.json";
|
|
|
|
|
var settings = new Settings
|
|
|
|
|
{
|
|
|
|
|
DataProtectionTitle = "isn",
|
|
|
|
|
Sources = new Dictionary<string, SourceSettings>
|
|
|
|
|
{
|
|
|
|
|
[expectedSource] = new SourceSettings { Alias = "override" }
|
|
|
|
|
},
|
|
|
|
|
DefaultSourceKey = expectedSource
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Environment.SetEnvironmentVariable("ISN_CONFIG_DIR", tempDir);
|
|
|
|
|
File.WriteAllText(configFile, JsonConvert.SerializeObject(settings, Formatting.Indented));
|
|
|
|
|
|
|
|
|
|
Program.LoadConfig();
|
|
|
|
|
|
|
|
|
|
Assert.Equal(expectedSource, Program.Settings.DefaultSourceKey);
|
|
|
|
|
Assert.True(Program.Settings.Sources.ContainsKey(expectedSource));
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
Environment.SetEnvironmentVariable("ISN_CONFIG_DIR", originalConfigDir);
|
|
|
|
|
if (Directory.Exists(tempDir))
|
|
|
|
|
{
|
|
|
|
|
Directory.Delete(tempDir, recursive: true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-11 19:57:30 +01:00
|
|
|
[Fact]
|
2023-01-29 13:04:50 +00:00
|
|
|
public void HaveADefaultDataProtector()
|
2021-08-15 05:31:38 +01:00
|
|
|
{
|
2026-07-05 18:16:52 +01:00
|
|
|
var pass = "a lame and big pass";
|
|
|
|
|
IDataProtector protector = new DefaultDataProtector();
|
|
|
|
|
var protectedpass = protector.Protect(pass);
|
|
|
|
|
var unprotectedpass = protector.UnProtect(protectedpass);
|
2021-08-15 05:31:38 +01:00
|
|
|
Console.WriteLine(protectedpass);
|
2022-04-11 19:57:30 +01:00
|
|
|
Assert.Equal(pass, unprotectedpass);
|
2022-09-23 20:34:51 +01:00
|
|
|
Assert.True(protectedpass != null);
|
|
|
|
|
Assert.True(protectedpass.Length > 0);
|
2021-08-15 05:31:38 +01:00
|
|
|
}
|
2021-09-03 03:07:58 +01:00
|
|
|
|
2022-04-11 19:57:30 +01:00
|
|
|
[Fact]
|
2022-04-11 01:48:43 +01:00
|
|
|
public async Task TestHttpClient()
|
|
|
|
|
{
|
2026-07-05 18:16:52 +01:00
|
|
|
using var client = new HttpClient();
|
|
|
|
|
var response = await client.GetAsync(fixture.SourceUrl);
|
2022-04-11 01:48:43 +01:00
|
|
|
var json = await response.Content.ReadAsStringAsync();
|
|
|
|
|
var vm = JsonConvert.DeserializeObject<ApiIndexViewModel>(json);
|
2022-09-23 20:34:51 +01:00
|
|
|
Console.WriteLine(JsonConvert.SerializeObject(vm));
|
2022-04-11 01:48:43 +01:00
|
|
|
Assert.NotNull(vm);
|
|
|
|
|
Assert.NotNull(vm.Resources);
|
|
|
|
|
}
|
2026-07-05 18:16:52 +01:00
|
|
|
|
2022-09-23 20:34:51 +01:00
|
|
|
[Fact]
|
2022-04-17 20:36:28 +01:00
|
|
|
public void TestPush()
|
2022-04-11 01:48:43 +01:00
|
|
|
{
|
2022-09-23 20:34:51 +01:00
|
|
|
Program.LoadConfig();
|
2026-07-05 23:23:04 +01:00
|
|
|
var report = Program.PushPkg(new[] { GetDummyPackagePath() });
|
2026-07-05 18:16:52 +01:00
|
|
|
Assert.NotNull(report);
|
|
|
|
|
Assert.Single(report);
|
2022-04-11 01:48:43 +01:00
|
|
|
}
|
2022-09-23 20:34:51 +01:00
|
|
|
|
2026-07-05 21:44:49 +01:00
|
|
|
[Fact]
|
|
|
|
|
public void PushUsesStoredApiKeyFromConfigWhenNoExplicitApiKeyIsProvided()
|
|
|
|
|
{
|
|
|
|
|
Program.LoadConfig();
|
|
|
|
|
var clearApiKey = "stored-api-key";
|
|
|
|
|
Program.Settings.Sources[fixture.SourceUrl].SetApiKey(clearApiKey);
|
|
|
|
|
Program.SaveConfig();
|
|
|
|
|
Program.LoadConfig();
|
|
|
|
|
|
2026-07-05 23:23:04 +01:00
|
|
|
var report = Program.PushPkg(new[] { GetDummyPackagePath() });
|
2026-07-05 21:44:49 +01:00
|
|
|
|
|
|
|
|
Assert.NotNull(report);
|
|
|
|
|
Assert.Single(report);
|
|
|
|
|
Assert.Equal(clearApiKey, fixture.LastApiKeyHeader);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-23 20:34:51 +01:00
|
|
|
[Fact]
|
2023-01-29 13:04:50 +00:00
|
|
|
public void GetServerResourcesUsingHttpClientAsyncTest()
|
2022-04-11 01:48:43 +01:00
|
|
|
{
|
2026-07-05 18:16:52 +01:00
|
|
|
var model = SourceHelpers.GetServerResources(fixture.SourceUrl);
|
2022-04-11 01:48:43 +01:00
|
|
|
Console.WriteLine(JsonConvert.SerializeObject(model));
|
|
|
|
|
Assert.NotNull(model.Resources);
|
2026-07-05 18:16:52 +01:00
|
|
|
var pub = model.Resources.FirstOrDefault(r => r.Type.StartsWith("PackagePublish/"));
|
2022-09-23 20:34:51 +01:00
|
|
|
Assert.True(pub != null);
|
2022-04-11 01:48:43 +01:00
|
|
|
}
|
2026-07-05 23:23:04 +01:00
|
|
|
|
|
|
|
|
private static string GetDummyPackagePath()
|
|
|
|
|
{
|
|
|
|
|
var localOutputDummy = Path.Combine(AppContext.BaseDirectory, "dummy.nupkg");
|
|
|
|
|
if (File.Exists(localOutputDummy))
|
|
|
|
|
{
|
|
|
|
|
return localOutputDummy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var dir = new DirectoryInfo(AppContext.BaseDirectory);
|
|
|
|
|
while (dir != null)
|
|
|
|
|
{
|
|
|
|
|
if (File.Exists(Path.Combine(dir.FullName, "isn.sln")))
|
|
|
|
|
{
|
|
|
|
|
var sharedArtifact = Path.Combine(dir.FullName, "test", "data", "nuget-artifacts", "dummy.nuget.1.0.0.nupkg");
|
|
|
|
|
if (File.Exists(sharedArtifact))
|
|
|
|
|
{
|
|
|
|
|
return sharedArtifact;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dir = dir.Parent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw new FileNotFoundException("Unable to locate a dummy NuGet package for push tests.");
|
|
|
|
|
}
|
2021-08-15 05:31:38 +01:00
|
|
|
}
|
|
|
|
|
}
|