fix(app): harden account and workflow state
This commit is contained in:
@@ -64,6 +64,26 @@ public sealed class JobImportServiceTests
|
||||
Assert.Equal("No JobPosting schema found.", result.Error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Preview_stops_reading_a_chunked_response_at_the_download_limit()
|
||||
{
|
||||
var resolver = new Mock<IHostAddressResolver>();
|
||||
resolver.Setup(x => x.ResolveAsync("example.com", It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync([IPAddress.Parse("93.184.216.34")]);
|
||||
var contentStream = new GeneratedStream(10_000_000);
|
||||
var handler = new StubHttpMessageHandler(_ => new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StreamContent(contentStream)
|
||||
});
|
||||
var service = CreateService(resolver.Object, handler);
|
||||
|
||||
var result = await service.PreviewAsync("https://example.com/job", CancellationToken.None);
|
||||
|
||||
Assert.False(result.Success);
|
||||
Assert.Equal("fetch", result.Parser);
|
||||
Assert.InRange(contentStream.BytesRead, 4_000_001, 4_065_536);
|
||||
}
|
||||
|
||||
private static JobImportService CreateService(IHostAddressResolver resolver, HttpMessageHandler? handler = null)
|
||||
{
|
||||
handler ??= new StubHttpMessageHandler(_ => new HttpResponseMessage(HttpStatusCode.OK)
|
||||
@@ -95,4 +115,37 @@ public sealed class JobImportServiceTests
|
||||
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
=> Task.FromResult(_handler(request));
|
||||
}
|
||||
|
||||
private sealed class GeneratedStream(long length) : Stream
|
||||
{
|
||||
private long _position;
|
||||
public long BytesRead { get; private set; }
|
||||
public override bool CanRead => true;
|
||||
public override bool CanSeek => false;
|
||||
public override bool CanWrite => false;
|
||||
public override long Length => length;
|
||||
public override long Position { get => _position; set => throw new NotSupportedException(); }
|
||||
public override void Flush() { }
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
var read = (int)Math.Min(count, length - _position);
|
||||
if (read <= 0) return 0;
|
||||
Array.Fill<byte>(buffer, (byte)'x', offset, read);
|
||||
_position += read;
|
||||
BytesRead += read;
|
||||
return read;
|
||||
}
|
||||
public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var read = (int)Math.Min(buffer.Length, length - _position);
|
||||
if (read <= 0) return ValueTask.FromResult(0);
|
||||
buffer.Span[..read].Fill((byte)'x');
|
||||
_position += read;
|
||||
BytesRead += read;
|
||||
return ValueTask.FromResult(read);
|
||||
}
|
||||
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
|
||||
public override void SetLength(long value) => throw new NotSupportedException();
|
||||
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user