Add unit tests for RabbitMq and Udp transport servers and clients
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
- Implemented comprehensive unit tests for RabbitMqTransportServer, covering constructor, disposal, connection management, event handlers, and exception handling. - Added configuration tests for RabbitMqTransportServer to validate SSL, durable queues, auto-recovery, and custom virtual host options. - Created unit tests for UdpFrameProtocol, including frame parsing and serialization, header size validation, and round-trip data preservation. - Developed tests for UdpTransportClient, focusing on connection handling, event subscriptions, and exception scenarios. - Established tests for UdpTransportServer, ensuring proper start/stop behavior, connection state management, and event handling. - Included tests for UdpTransportOptions to verify default values and modification capabilities. - Enhanced service registration tests for Udp transport services in the dependency injection container.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using StellaOps.Cryptography;
|
||||
using StellaOps.Policy.RiskProfile.Hashing;
|
||||
using StellaOps.Policy.RiskProfile.Lifecycle;
|
||||
using StellaOps.Policy.RiskProfile.Models;
|
||||
@@ -17,6 +18,7 @@ public sealed class ProfileExportService
|
||||
private const string DefaultAlgorithm = "HMAC-SHA256";
|
||||
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly ICryptoHash _cryptoHash;
|
||||
private readonly RiskProfileHasher _hasher;
|
||||
private readonly Func<string, RiskProfileModel?>? _profileLookup;
|
||||
private readonly Func<string, RiskProfileVersionInfo?>? _lifecycleLookup;
|
||||
@@ -30,14 +32,16 @@ public sealed class ProfileExportService
|
||||
};
|
||||
|
||||
public ProfileExportService(
|
||||
ICryptoHash cryptoHash,
|
||||
TimeProvider? timeProvider = null,
|
||||
Func<string, RiskProfileModel?>? profileLookup = null,
|
||||
Func<string, RiskProfileVersionInfo?>? lifecycleLookup = null,
|
||||
Action<RiskProfileModel>? profileSave = null,
|
||||
Func<string, string?>? keyLookup = null)
|
||||
{
|
||||
_cryptoHash = cryptoHash ?? throw new ArgumentNullException(nameof(cryptoHash));
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
_hasher = new RiskProfileHasher();
|
||||
_hasher = new RiskProfileHasher(cryptoHash);
|
||||
_profileLookup = profileLookup;
|
||||
_lifecycleLookup = lifecycleLookup;
|
||||
_profileSave = profileSave;
|
||||
@@ -331,15 +335,14 @@ public sealed class ProfileExportService
|
||||
.ThenBy(p => p.Profile.Version)
|
||||
.Select(p => p.ContentHash));
|
||||
|
||||
var hashBytes = SHA256.HashData(Encoding.UTF8.GetBytes(combined));
|
||||
return Convert.ToHexStringLower(hashBytes);
|
||||
return _cryptoHash.ComputeHashHexForPurpose(Encoding.UTF8.GetBytes(combined), HashPurpose.Content);
|
||||
}
|
||||
|
||||
private static string GenerateBundleId(DateTimeOffset timestamp)
|
||||
private string GenerateBundleId(DateTimeOffset timestamp)
|
||||
{
|
||||
var seed = $"{timestamp:O}|{Guid.NewGuid()}";
|
||||
var hash = SHA256.HashData(Encoding.UTF8.GetBytes(seed));
|
||||
return $"rpb-{Convert.ToHexStringLower(hash)[..16]}";
|
||||
var hash = _cryptoHash.ComputeHashHexForPurpose(Encoding.UTF8.GetBytes(seed), HashPurpose.Content);
|
||||
return $"rpb-{hash[..16]}";
|
||||
}
|
||||
|
||||
private static string GetSourceVersion()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using StellaOps.Cryptography;
|
||||
using StellaOps.Policy.RiskProfile.Models;
|
||||
|
||||
namespace StellaOps.Policy.RiskProfile.Hashing;
|
||||
@@ -11,6 +11,8 @@ namespace StellaOps.Policy.RiskProfile.Hashing;
|
||||
/// </summary>
|
||||
public sealed class RiskProfileHasher
|
||||
{
|
||||
private readonly ICryptoHash _cryptoHash;
|
||||
|
||||
private static readonly JsonSerializerOptions CanonicalJsonOptions = new()
|
||||
{
|
||||
WriteIndented = false,
|
||||
@@ -22,20 +24,24 @@ public sealed class RiskProfileHasher
|
||||
},
|
||||
};
|
||||
|
||||
public RiskProfileHasher(ICryptoHash cryptoHash)
|
||||
{
|
||||
_cryptoHash = cryptoHash ?? throw new ArgumentNullException(nameof(cryptoHash));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes a deterministic SHA-256 hash of the risk profile.
|
||||
/// Computes a deterministic hash of the risk profile using the compliance profile's content algorithm.
|
||||
/// </summary>
|
||||
/// <param name="profile">The profile to hash.</param>
|
||||
/// <returns>Lowercase hex-encoded SHA-256 hash.</returns>
|
||||
/// <returns>Lowercase hex-encoded hash.</returns>
|
||||
public string ComputeHash(RiskProfileModel profile)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(profile);
|
||||
|
||||
var canonical = CreateCanonicalForm(profile);
|
||||
var json = JsonSerializer.Serialize(canonical, CanonicalJsonOptions);
|
||||
var hash = SHA256.HashData(Encoding.UTF8.GetBytes(json));
|
||||
|
||||
return Convert.ToHexStringLower(hash);
|
||||
return _cryptoHash.ComputeHashHexForPurpose(Encoding.UTF8.GetBytes(json), HashPurpose.Content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -43,16 +49,15 @@ public sealed class RiskProfileHasher
|
||||
/// Useful for detecting semantic changes regardless of versioning.
|
||||
/// </summary>
|
||||
/// <param name="profile">The profile to hash.</param>
|
||||
/// <returns>Lowercase hex-encoded SHA-256 hash.</returns>
|
||||
/// <returns>Lowercase hex-encoded hash.</returns>
|
||||
public string ComputeContentHash(RiskProfileModel profile)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(profile);
|
||||
|
||||
var canonical = CreateCanonicalContentForm(profile);
|
||||
var json = JsonSerializer.Serialize(canonical, CanonicalJsonOptions);
|
||||
var hash = SHA256.HashData(Encoding.UTF8.GetBytes(json));
|
||||
|
||||
return Convert.ToHexStringLower(hash);
|
||||
return _cryptoHash.ComputeHashHexForPurpose(Encoding.UTF8.GetBytes(json), HashPurpose.Content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using StellaOps.Cryptography;
|
||||
using StellaOps.Policy.RiskProfile.Hashing;
|
||||
using StellaOps.Policy.RiskProfile.Models;
|
||||
|
||||
@@ -16,10 +15,11 @@ public sealed class RiskProfileLifecycleService
|
||||
private readonly ConcurrentDictionary<string, List<RiskProfileVersionInfo>> _versions;
|
||||
private readonly ConcurrentDictionary<string, List<RiskProfileLifecycleEvent>> _events;
|
||||
|
||||
public RiskProfileLifecycleService(TimeProvider? timeProvider = null)
|
||||
public RiskProfileLifecycleService(ICryptoHash cryptoHash, TimeProvider? timeProvider = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(cryptoHash);
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
_hasher = new RiskProfileHasher();
|
||||
_hasher = new RiskProfileHasher(cryptoHash);
|
||||
_versions = new ConcurrentDictionary<string, List<RiskProfileVersionInfo>>(StringComparer.OrdinalIgnoreCase);
|
||||
_events = new ConcurrentDictionary<string, List<RiskProfileLifecycleEvent>>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
<PackageReference Include="JsonSchema.Net" Version="5.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Cryptography/StellaOps.Cryptography.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Schemas\risk-profile-schema@1.json" />
|
||||
</ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user