Skip to content

Commit

Permalink
Rename test symbols
Browse files Browse the repository at this point in the history
  • Loading branch information
w1am committed Jan 7, 2025
1 parent 0c2d0e3 commit ebc6e60
Show file tree
Hide file tree
Showing 331 changed files with 15,042 additions and 440 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/base.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ jobs:
uses: actions/setup-dotnet@v3
with:
dotnet-version: |
8.0.x
9.0.x
- name: Run Tests
shell: bash
env:
Expand All @@ -64,7 +64,7 @@ jobs:
dotnet test --configuration ${{ matrix.configuration }} --blame \
--logger:"GitHubActions;report-warnings=false" --logger:"console;verbosity=normal" \
--framework ${{ matrix.framework }} \
test/EventStore.Client.Tests
test/Kurrent.Client.Tests
# run: |
# sudo ./gencert.sh
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ jobs:
strategy:
fail-fast: false
matrix:
docker-tag: [ ci, lts, previous-lts ]
# docker-tag: [ ci, lts, previous-lts ]
docker-tag: [ ci ]
# test: [ Streams, PersistentSubscriptions, Operations, UserManagement, ProjectionManagement ]
name: Test CE (${{ matrix.docker-tag }})
with:
Expand Down
23 changes: 15 additions & 8 deletions EventStore.Client.sln → Kurrent.Client.sln
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventStore.Client", "src\Ev
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C51F2C69-45A9-4D0D-A708-4FC319D5D340}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventStore.Client.Tests", "test\EventStore.Client.Tests\EventStore.Client.Tests.csproj", "{FC829F1B-43AD-4C96-9002-23D04BBA3AF3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventStore.Client.Tests.Common", "test\EventStore.Client.Tests.Common\EventStore.Client.Tests.Common.csproj", "{E326832D-DE52-4DE4-9E54-C800908B75F3}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kurrent.Client.Tests", "test\Kurrent.Client.Tests\Kurrent.Client.Tests.csproj", "{FC829F1B-43AD-4C96-9002-23D04BBA3AF3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EventStore.Client.Extensions.OpenTelemetry", "src\EventStore.Client.Extensions.OpenTelemetry\EventStore.Client.Extensions.OpenTelemetry.csproj", "{F6A7B391-36F1-4838-AD08-E0EE0F2FE57E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kurrent.Client", "src\Kurrent.Client\Kurrent.Client.csproj", "{762EECAA-122E-4B0C-BC50-5AA4F72CA4E0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kurrent.Client.Tests.Common", "test\Kurrent.Client.Tests.Common\Kurrent.Client.Tests.Common.csproj", "{47BF715B-A0BF-4044-B335-717E56422550}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Expand All @@ -32,19 +34,24 @@ Global
{FC829F1B-43AD-4C96-9002-23D04BBA3AF3}.Debug|x64.Build.0 = Debug|Any CPU
{FC829F1B-43AD-4C96-9002-23D04BBA3AF3}.Release|x64.ActiveCfg = Release|Any CPU
{FC829F1B-43AD-4C96-9002-23D04BBA3AF3}.Release|x64.Build.0 = Release|Any CPU
{E326832D-DE52-4DE4-9E54-C800908B75F3}.Debug|x64.ActiveCfg = Debug|Any CPU
{E326832D-DE52-4DE4-9E54-C800908B75F3}.Debug|x64.Build.0 = Debug|Any CPU
{E326832D-DE52-4DE4-9E54-C800908B75F3}.Release|x64.ActiveCfg = Release|Any CPU
{E326832D-DE52-4DE4-9E54-C800908B75F3}.Release|x64.Build.0 = Release|Any CPU
{F6A7B391-36F1-4838-AD08-E0EE0F2FE57E}.Debug|x64.ActiveCfg = Debug|Any CPU
{F6A7B391-36F1-4838-AD08-E0EE0F2FE57E}.Debug|x64.Build.0 = Debug|Any CPU
{F6A7B391-36F1-4838-AD08-E0EE0F2FE57E}.Release|x64.ActiveCfg = Release|Any CPU
{F6A7B391-36F1-4838-AD08-E0EE0F2FE57E}.Release|x64.Build.0 = Release|Any CPU
{762EECAA-122E-4B0C-BC50-5AA4F72CA4E0}.Debug|x64.ActiveCfg = Debug|Any CPU
{762EECAA-122E-4B0C-BC50-5AA4F72CA4E0}.Debug|x64.Build.0 = Debug|Any CPU
{762EECAA-122E-4B0C-BC50-5AA4F72CA4E0}.Release|x64.ActiveCfg = Release|Any CPU
{762EECAA-122E-4B0C-BC50-5AA4F72CA4E0}.Release|x64.Build.0 = Release|Any CPU
{47BF715B-A0BF-4044-B335-717E56422550}.Debug|x64.ActiveCfg = Debug|Any CPU
{47BF715B-A0BF-4044-B335-717E56422550}.Debug|x64.Build.0 = Debug|Any CPU
{47BF715B-A0BF-4044-B335-717E56422550}.Release|x64.ActiveCfg = Release|Any CPU
{47BF715B-A0BF-4044-B335-717E56422550}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{8853D875-4A8E-450B-A1BE-9CEF8BEDABC3} = {EA59C1CB-16DA-4F68-AF8A-642A969B4CF8}
{FC829F1B-43AD-4C96-9002-23D04BBA3AF3} = {C51F2C69-45A9-4D0D-A708-4FC319D5D340}
{E326832D-DE52-4DE4-9E54-C800908B75F3} = {C51F2C69-45A9-4D0D-A708-4FC319D5D340}
{F6A7B391-36F1-4838-AD08-E0EE0F2FE57E} = {EA59C1CB-16DA-4F68-AF8A-642A969B4CF8}
{762EECAA-122E-4B0C-BC50-5AA4F72CA4E0} = {EA59C1CB-16DA-4F68-AF8A-642A969B4CF8}
{47BF715B-A0BF-4044-B335-717E56422550} = {C51F2C69-45A9-4D0D-A708-4FC319D5D340}
EndGlobalSection
EndGlobal
File renamed without changes.
8 changes: 4 additions & 4 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@

<PropertyGroup>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<RootNamespace>EventStore.Client</RootNamespace>
<PackageId>EventStore.Client</PackageId>
<RootNamespace>Kurrent.Client</RootNamespace>
<PackageId>Kurrent.Client</PackageId>
</PropertyGroup>

<PropertyGroup>
<PackageIcon>ouro.png</PackageIcon>
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
<PackageProjectUrl>https://kurrent.io</PackageProjectUrl>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<PackageReleaseNotes>https://eventstore.com/blog/</PackageReleaseNotes>
<PackageTags>kurrent eventstore client grpc</PackageTags>
<PackageReleaseNotes>https://kurrent.io/blog/</PackageReleaseNotes>
<PackageTags>kurrent client grpc</PackageTags>
<Authors>Kurrent Ltd</Authors>
<Copyright>Copyright 2012-$([System.DateTime]::Today.Year.ToString()) Kurrent Ltd</Copyright>
<MinVerTagPrefix>v</MinVerTagPrefix>
Expand Down
114 changes: 114 additions & 0 deletions src/Kurrent.Client/Core/Certificates/X509Certificates.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member

using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

#if NET48
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
#endif

namespace EventStore.Client;

static class X509Certificates {
// TODO SS: Use .NET 8 X509Certificate2.CreateFromPemFile(certPemFilePath, keyPemFilePath) once the Windows32Exception issue is resolved
public static X509Certificate2 CreateFromPemFile(string certPemFilePath, string keyPemFilePath) {
try {
#if NET9_0_OR_GREATER
using var publicCert = X509CertificateLoader.LoadCertificateFromFile(certPemFilePath);
#else
using var publicCert = new X509Certificate2(certPemFilePath);
#endif
using var privateKey = RSA.Create().ImportPrivateKeyFromFile(keyPemFilePath);
using var certificate = publicCert.CopyWithPrivateKey(privateKey);

#if NET48
return new(certificate.Export(X509ContentType.Pfx));
#else
return X509Certificate2.CreateFromPemFile(certPemFilePath, keyPemFilePath);
#endif
} catch (Exception ex) {
throw new CryptographicException($"Failed to load private key: {ex.Message}");
}

// Notes:
// using X509Certificate2.CreateFromPemFile(certPemFilePath, keyPemFilePath) would be the ideal choice here,
// but it's currently causing a Win32Exception specifically on Windows. Alternative implementation is used until the issue is resolved.
//
// Error: The SSL connection could not be established, see inner exception. AuthenticationException: Authentication failed because the platform
// does not support ephemeral keys. Win32Exception: No credentials are available in the security package
//
// public static X509Certificate2 CreateFromPemFile(string certPemFilePath, string keyPemFilePath) =>
// X509Certificate2.CreateFromPemFile(certPemFilePath, keyPemFilePath);
}
}

public static class RsaExtensions {
#if NET48
public static RSA ImportPrivateKeyFromFile(this RSA rsa, string privateKeyPath) {
var (content, label) = LoadPemKeyFile(privateKeyPath);

using var reader = new PemReader(new StringReader(string.Join(Environment.NewLine, content)));

var keyParameters = reader.ReadObject() switch {
RsaPrivateCrtKeyParameters parameters => parameters,
AsymmetricCipherKeyPair keyPair => keyPair.Private as RsaPrivateCrtKeyParameters,
_ => throw new NotSupportedException($"Invalid private key format: {label}")
};

rsa.ImportParameters(DotNetUtilities.ToRSAParameters(keyParameters));

return rsa;
}
#else
public static RSA ImportPrivateKeyFromFile(this RSA rsa, string privateKeyPath) {
var (content, label) = LoadPemKeyFile(privateKeyPath);

var privateKey = string.Join(string.Empty, content[1..^1]);
var privateKeyBytes = Convert.FromBase64String(privateKey);

if (label == RsaPemLabels.Pkcs8PrivateKey)
rsa.ImportPkcs8PrivateKey(privateKeyBytes, out _);
else if (label == RsaPemLabels.RSAPrivateKey)
rsa.ImportRSAPrivateKey(privateKeyBytes, out _);

return rsa;
}
#endif

static (string[] Content, string Label) LoadPemKeyFile(string privateKeyPath) {
var content = File.ReadAllLines(privateKeyPath);
var label = RsaPemLabels.ParseKeyLabel(content[0]);

if (RsaPemLabels.IsEncryptedPrivateKey(label))
throw new NotSupportedException("Encrypted private keys are not supported");

return (content, label);
}
}

static class RsaPemLabels {
public const string RSAPrivateKey = "RSA PRIVATE KEY";
public const string Pkcs8PrivateKey = "PRIVATE KEY";
public const string EncryptedPkcs8PrivateKey = "ENCRYPTED PRIVATE KEY";

public static readonly string[] PrivateKeyLabels = [RSAPrivateKey, Pkcs8PrivateKey, EncryptedPkcs8PrivateKey];

public static bool IsPrivateKey(string label) => Array.IndexOf(PrivateKeyLabels, label) != -1;

public static bool IsEncryptedPrivateKey(string label) => label == EncryptedPkcs8PrivateKey;

const string LabelPrefix = "-----BEGIN ";
const string LabelSuffix = "-----";

public static string ParseKeyLabel(string pemFileHeader) {
var label = pemFileHeader.Replace(LabelPrefix, string.Empty).Replace(LabelSuffix, string.Empty);

if (!IsPrivateKey(label))
throw new CryptographicException($"Unknown private key label: {label}");

return label;
}
}
10 changes: 10 additions & 0 deletions src/Kurrent.Client/Core/ChannelBaseExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Grpc.Core;

namespace EventStore.Client;

static class ChannelBaseExtensions {
public static async ValueTask DisposeAsync(this ChannelBase channel) {
await channel.ShutdownAsync().ConfigureAwait(false);
(channel as IDisposable)?.Dispose();
}
}
146 changes: 146 additions & 0 deletions src/Kurrent.Client/Core/ChannelCache.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
using System.Net;
using TChannel = Grpc.Net.Client.GrpcChannel;

namespace EventStore.Client {
// Maintains Channels keyed by DnsEndPoint so the channels can be reused.
// Deals with the disposal difference between grpc.net and grpc.core
// Thread safe.
internal class ChannelCache :
IAsyncDisposable {

private readonly KurrentClientSettings _settings;
private readonly Random _random;
private readonly Dictionary<DnsEndPoint, TChannel> _channels;
private readonly object _lock = new();
private bool _disposed;

public ChannelCache(KurrentClientSettings settings) {
_settings = settings;
_random = new Random(0);
_channels = new Dictionary<DnsEndPoint, TChannel>(
DnsEndPointEqualityComparer.Instance);
}

public TChannel GetChannelInfo(DnsEndPoint endPoint) {
lock (_lock) {
ThrowIfDisposed();

if (!_channels.TryGetValue(endPoint, out var channel)) {
channel = ChannelFactory.CreateChannel(
settings: _settings,
endPoint: endPoint);
_channels[endPoint] = channel;
}

return channel;
}
}

public KeyValuePair<DnsEndPoint, TChannel>[] GetRandomOrderSnapshot() {
lock (_lock) {
ThrowIfDisposed();

return _channels
.OrderBy(_ => _random.Next())
.ToArray();
}
}

// Update the cache to contain channels for exactly these endpoints
public void UpdateCache(IEnumerable<DnsEndPoint> endPoints) {
lock (_lock) {
ThrowIfDisposed();

// remove
var endPointsToDiscard = _channels.Keys
.Except(endPoints, DnsEndPointEqualityComparer.Instance)
.ToArray();

var channelsToDispose = new List<TChannel>(endPointsToDiscard.Length);

foreach (var endPoint in endPointsToDiscard) {
if (!_channels.TryGetValue(endPoint, out var channel))
continue;

_channels.Remove(endPoint);
channelsToDispose.Add(channel);
}

_ = DisposeChannelsAsync(channelsToDispose);

// add
foreach (var endPoint in endPoints) {
GetChannelInfo(endPoint);
}
}
}

public void Dispose() {
lock (_lock) {
if (_disposed)
return;

_disposed = true;

foreach (var channel in _channels.Values) {
channel.Dispose();
}

_channels.Clear();
}
}

public async ValueTask DisposeAsync() {
var channelsToDispose = Array.Empty<TChannel>();

lock (_lock) {
if (_disposed)
return;
_disposed = true;

channelsToDispose = _channels.Values.ToArray();
_channels.Clear();
}

await DisposeChannelsAsync(channelsToDispose).ConfigureAwait(false);
}

private void ThrowIfDisposed() {
lock (_lock) {
if (_disposed) {
throw new ObjectDisposedException(GetType().ToString());
}
}
}

private static async Task DisposeChannelsAsync(IEnumerable<TChannel> channels) {
foreach (var channel in channels)
await channel.DisposeAsync().ConfigureAwait(false);
}

private class DnsEndPointEqualityComparer : IEqualityComparer<DnsEndPoint> {
public static readonly DnsEndPointEqualityComparer Instance = new();

public bool Equals(DnsEndPoint? x, DnsEndPoint? y) {
if (ReferenceEquals(x, y))
return true;
if (x is null)
return false;
if (y is null)
return false;
if (x.GetType() != y.GetType())
return false;
return
string.Equals(x.Host, y.Host, StringComparison.OrdinalIgnoreCase) &&
x.Port == y.Port;
}

public int GetHashCode(DnsEndPoint obj) {
unchecked {
return (StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Host) * 397) ^
obj.Port;
}
}
}
}
}
Loading

0 comments on commit ebc6e60

Please sign in to comment.