159 lines
5.5 KiB
C#
159 lines
5.5 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Paca.Core;
|
|
using Paca.Core.Utils;
|
|
using Xunit;
|
|
|
|
namespace Paca.Tests.Core;
|
|
|
|
public class StreamingAndResourceGuardianExtremeRedTests
|
|
{
|
|
// ==========================================
|
|
// 1. TranscodeProfileManager & ThermalGuard
|
|
// ==========================================
|
|
|
|
[Theory]
|
|
[InlineData(null)]
|
|
[InlineData("")]
|
|
[InlineData(" ")]
|
|
public void TranscodeProfileManager_GetFfmpegProfileArgs_NullOrWhitespace_ReturnsCopySafeFallback(string? badProfile)
|
|
{
|
|
var manager = new TranscodeProfileManager();
|
|
var args = manager.GetFfmpegProfileArgs(badProfile!);
|
|
Assert.NotNull(args);
|
|
Assert.Equal("-c copy", args);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0)]
|
|
[InlineData(-5)]
|
|
public void ThermalThrottlingGuard_AdjustedSegments_ZeroOrNegativeRequested_ReturnsAtLeastOne(int badSegments)
|
|
{
|
|
var guard = new ThermalThrottlingGuard();
|
|
int adjusted = guard.GetAdjustedSegments(badSegments, 25.0); // Normal temp
|
|
Assert.True(adjusted >= 1, "Segments must be at least 1 even if requested was <= 0");
|
|
}
|
|
|
|
// ==========================================
|
|
// 2. RemoteStreamProxyBuffer Bound & Safety
|
|
// ==========================================
|
|
|
|
[Fact]
|
|
public void RemoteStreamProxyBuffer_NullData_DoesNotThrowNullReference()
|
|
{
|
|
var buffer = new RemoteStreamProxyBuffer(1024);
|
|
var ex = Record.Exception(() => buffer.Write(null!));
|
|
Assert.Null(ex);
|
|
Assert.Equal(0, buffer.BufferedBytes);
|
|
}
|
|
|
|
[Fact]
|
|
public void RemoteStreamProxyBuffer_ExceedingCapacity_EvictsOldestBytesToRespectCapacity()
|
|
{
|
|
const int capacity = 100;
|
|
var buffer = new RemoteStreamProxyBuffer(capacity);
|
|
|
|
// Write 60 bytes of 0x01
|
|
byte[] chunk1 = new byte[60];
|
|
Array.Fill(chunk1, (byte)1);
|
|
buffer.Write(chunk1);
|
|
Assert.Equal(60, buffer.BufferedBytes);
|
|
|
|
// Write 60 bytes of 0x02 (Total would be 120, exceeding capacity 100)
|
|
byte[] chunk2 = new byte[60];
|
|
Array.Fill(chunk2, (byte)2);
|
|
buffer.Write(chunk2);
|
|
|
|
// Capacity must NOT be exceeded
|
|
Assert.True(buffer.BufferedBytes <= capacity, $"Buffered bytes ({buffer.BufferedBytes}) must not exceed capacity ({capacity})");
|
|
|
|
// Reading remaining bytes should contain the newer bytes (0x02)
|
|
byte[] readTarget = new byte[capacity];
|
|
int readCount = buffer.Read(readTarget, 0, capacity);
|
|
Assert.Equal(buffer.CapacityBytes, readCount);
|
|
Assert.Equal(2, readTarget[readCount - 1]); // Last byte must be from chunk2
|
|
}
|
|
|
|
// ==========================================
|
|
// 3. DiskSpaceGuardian OS HResult & Unnesting
|
|
// ==========================================
|
|
|
|
[Fact]
|
|
public void DiskSpaceGuardian_IsDiskFullException_HResultCheck_ReturnsTrueEvenWithUnknownLanguageMessage()
|
|
{
|
|
// 0x80070070 = HRESULT for ERROR_DISK_FULL (112)
|
|
var foreignEx = new IOException("Espace disque insuffisant sur le lecteur C:", unchecked((int)0x80070070));
|
|
bool isFull = DiskSpaceGuardian.IsDiskFullException(foreignEx);
|
|
Assert.True(isFull, "Must detect disk full via HResult 0x80070070 regardless of OS language");
|
|
}
|
|
|
|
[Fact]
|
|
public void DiskSpaceGuardian_IsDiskFullException_WrappedInAggregateException_DetectsInnerDiskFull()
|
|
{
|
|
var inner = new IOException("There is not enough space on the disk.");
|
|
var aggregate = new AggregateException("Task failed", inner);
|
|
bool isFull = DiskSpaceGuardian.IsDiskFullException(aggregate);
|
|
Assert.True(isFull, "Must unnest AggregateException to find inner disk full exception");
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0)]
|
|
[InlineData(-100)]
|
|
public void DiskSpaceGuardian_HasSufficientSpace_ZeroOrNegativeBytes_ReturnsTrue(long bytes)
|
|
{
|
|
bool result = DiskSpaceGuardian.HasSufficientSpace("C:\\fake\\path.mp4", bytes);
|
|
Assert.True(result);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(null)]
|
|
[InlineData("")]
|
|
[InlineData(" ")]
|
|
public void DiskSpaceGuardian_HasSufficientSpace_NullOrWhitespacePath_ReturnsTrue(string? badPath)
|
|
{
|
|
bool result = DiskSpaceGuardian.HasSufficientSpace(badPath!, 1024);
|
|
Assert.True(result);
|
|
}
|
|
|
|
// ==========================================
|
|
// 4. ThrottledStream & BufferPool Safety
|
|
// ==========================================
|
|
|
|
[Fact]
|
|
public void ThrottledStream_NullBaseStream_ThrowsArgumentNullException()
|
|
{
|
|
Assert.Throws<ArgumentNullException>(() => new ThrottledStream(null!, 1024));
|
|
}
|
|
|
|
[Fact]
|
|
public void ThrottledStream_ZeroOrNegativeMaxBytes_DoesNotThrowAndReadsNormally()
|
|
{
|
|
byte[] source = new byte[] { 1, 2, 3, 4, 5 };
|
|
using var ms = new MemoryStream(source);
|
|
using var throttled = new ThrottledStream(ms, maxBytesPerSecond: 0); // Unthrottled
|
|
|
|
byte[] dest = new byte[5];
|
|
int read = throttled.Read(dest, 0, 5);
|
|
Assert.Equal(5, read);
|
|
Assert.Equal(source, dest);
|
|
}
|
|
|
|
[Fact]
|
|
public void BufferPoolManager_Return_NullArray_DoesNotThrow()
|
|
{
|
|
var ex = Record.Exception(() => BufferPoolManager.Return(null!));
|
|
Assert.Null(ex);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0)]
|
|
[InlineData(-100)]
|
|
public void AdaptiveChunkSizingEngine_NegativeOrZeroSpeed_ReturnsMinimum512KB(int speed)
|
|
{
|
|
var engine = new AdaptiveChunkSizingEngine();
|
|
int size = engine.CalculateOptimalChunkSize(speed);
|
|
Assert.Equal(512 * 1024, size);
|
|
}
|
|
}
|