7b0b9c7365
Solution + 23 src projects + 26 test projects renamed; folders, csproj, namespaces, and ScadaLinkDbContext/ScadaBridgeDbContext class updated. ActorSystem "scadalink" → "scadabridge", Akka seed-node URLs migrated. SQL roles/logins, LDAP domains, CLI command name, and CLI config dir (~/.scadalink → ~/.scadabridge) also renamed. Build green; 5 Host.Tests fail awaiting SQL login rename in next commit. Pre-existing StaleTagMonitor timing flakes unchanged. Rename script committed at tools/rename-to-scadabridge.sh.
95 lines
3.2 KiB
C#
95 lines
3.2 KiB
C#
using ZB.MOM.WW.ScadaBridge.CLI.Commands;
|
|
|
|
namespace ZB.MOM.WW.ScadaBridge.CLI.Tests.Commands;
|
|
|
|
/// <summary>
|
|
/// CLI-019 regression tests for <see cref="BundleCommands.StreamBase64ToFile"/>.
|
|
/// The pre-fix code did <c>Convert.FromBase64String(...) → File.WriteAllBytes(...)</c>,
|
|
/// doubling the bundle's bytes onto the LOH and writing synchronously. The new
|
|
/// streaming helper decodes the base64 string in fixed-size chunks straight into
|
|
/// a <see cref="FileStream"/>, so peak working set is bounded by the chunk size
|
|
/// regardless of how large the bundle is.
|
|
/// </summary>
|
|
public class BundleCommandsStreamingTests : IDisposable
|
|
{
|
|
private readonly string _tempPath;
|
|
|
|
public BundleCommandsStreamingTests()
|
|
{
|
|
_tempPath = Path.Combine(Path.GetTempPath(), $"bundle-stream-test-{Guid.NewGuid():N}.bin");
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (File.Exists(_tempPath))
|
|
{
|
|
File.Delete(_tempPath);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void StreamBase64ToFile_SmallPayload_RoundTrips()
|
|
{
|
|
var bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
|
|
var base64 = Convert.ToBase64String(bytes);
|
|
|
|
var written = BundleCommands.StreamBase64ToFile(base64, _tempPath);
|
|
|
|
Assert.Equal(bytes.Length, written);
|
|
var roundTripped = File.ReadAllBytes(_tempPath);
|
|
Assert.Equal(bytes, roundTripped);
|
|
}
|
|
|
|
[Fact]
|
|
public void StreamBase64ToFile_PayloadCrossesChunkBoundary_RoundTrips()
|
|
{
|
|
// Build a payload several chunks wide so the slicing loop runs more than
|
|
// once, with enough trailing bytes that the final slice is short and
|
|
// exercises the padding/short-final-chunk path.
|
|
var size = (BundleCommands.Base64StreamChunkChars / 4 * 3) * 3 + 17;
|
|
var bytes = new byte[size];
|
|
for (var i = 0; i < size; i++) bytes[i] = (byte)(i & 0xFF);
|
|
|
|
var base64 = Convert.ToBase64String(bytes);
|
|
|
|
var written = BundleCommands.StreamBase64ToFile(base64, _tempPath);
|
|
|
|
Assert.Equal(size, written);
|
|
var roundTripped = File.ReadAllBytes(_tempPath);
|
|
Assert.Equal(bytes, roundTripped);
|
|
}
|
|
|
|
[Fact]
|
|
public void StreamBase64ToFile_EmptyString_WritesEmptyFile()
|
|
{
|
|
var written = BundleCommands.StreamBase64ToFile(string.Empty, _tempPath);
|
|
|
|
Assert.Equal(0, written);
|
|
Assert.True(File.Exists(_tempPath));
|
|
Assert.Empty(File.ReadAllBytes(_tempPath));
|
|
}
|
|
|
|
[Fact]
|
|
public void StreamBase64ToFile_InvalidBase64_ThrowsFormatException()
|
|
{
|
|
// '*' is not a valid base64 character, so TryFromBase64Chars returns
|
|
// false and the helper throws — the pre-fix code threw FormatException
|
|
// from Convert.FromBase64String, so the contract is preserved.
|
|
var invalid = "this is not valid base64 !!!*";
|
|
|
|
Assert.Throws<FormatException>(() => BundleCommands.StreamBase64ToFile(invalid, _tempPath));
|
|
}
|
|
|
|
[Fact]
|
|
public void StreamBase64ToFile_NullBase64_Throws()
|
|
{
|
|
Assert.Throws<ArgumentNullException>(() => BundleCommands.StreamBase64ToFile(null!, _tempPath));
|
|
}
|
|
|
|
[Fact]
|
|
public void StreamBase64ToFile_EmptyOutputPath_Throws()
|
|
{
|
|
Assert.Throws<ArgumentException>(() => BundleCommands.StreamBase64ToFile("AAAA", string.Empty));
|
|
}
|
|
}
|