fix(worker): cap run-log read size and harden run-history tests
- GetTaskLog reads at most last 256 KB; prepends truncation marker if file exceeds cap - Wrap temp-file cleanup in finally block to prevent leak on assertion failure - Add GetRun_NotFound_Throws, GetTaskLog_RunExistsButNoLogPath_Throws, and GetTaskLog_LargeFile_ReturnsTruncatedTail tests Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -76,9 +76,71 @@ public sealed class RunHistoryMcpToolsTests : IDisposable
|
||||
IsRetry = false, Prompt = "p", LogPath = logPath,
|
||||
});
|
||||
|
||||
var content = await _sut.GetTaskLog(taskId, CancellationToken.None);
|
||||
string content;
|
||||
try
|
||||
{
|
||||
content = await _sut.GetTaskLog(taskId, CancellationToken.None);
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(logPath);
|
||||
}
|
||||
|
||||
Assert.Equal("hello log", content);
|
||||
File.Delete(logPath);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetRun_NotFound_Throws()
|
||||
{
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
||||
_sut.GetRun("missing", CancellationToken.None));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetTaskLog_RunExistsButNoLogPath_Throws()
|
||||
{
|
||||
var taskId = Guid.NewGuid().ToString();
|
||||
await SeedTaskAsync(taskId);
|
||||
await _runs.AddAsync(new TaskRunEntity
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(), TaskId = taskId, RunNumber = 1,
|
||||
IsRetry = false, Prompt = "p", LogPath = null,
|
||||
});
|
||||
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
||||
_sut.GetTaskLog(taskId, CancellationToken.None));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetTaskLog_LargeFile_ReturnsTruncatedTail()
|
||||
{
|
||||
var taskId = Guid.NewGuid().ToString();
|
||||
await SeedTaskAsync(taskId);
|
||||
var logPath = Path.Combine(Path.GetTempPath(), $"claudedo_log_{Guid.NewGuid():N}.txt");
|
||||
|
||||
// Write 300 KB so it exceeds the 256 KB cap
|
||||
var chunk = new string('A', 1024);
|
||||
await using (var w = new StreamWriter(logPath, append: false))
|
||||
for (var i = 0; i < 300; i++)
|
||||
await w.WriteAsync(chunk);
|
||||
|
||||
await _runs.AddAsync(new TaskRunEntity
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(), TaskId = taskId, RunNumber = 1,
|
||||
IsRetry = false, Prompt = "p", LogPath = logPath,
|
||||
});
|
||||
|
||||
string content;
|
||||
try
|
||||
{
|
||||
content = await _sut.GetTaskLog(taskId, CancellationToken.None);
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(logPath);
|
||||
}
|
||||
|
||||
Assert.StartsWith("[truncated:", content);
|
||||
Assert.True(content.Length < 300 * 1024);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user