cs-codex-dist-tests/Framework/FileUtils/FileManager.cs

158 lines
4.6 KiB
C#
Raw Normal View History

2023-04-12 14:06:04 +00:00
using Logging;
using Utils;
2023-04-12 14:06:04 +00:00
namespace FileUtils
2023-04-12 14:06:04 +00:00
{
public interface IFileManager
{
2023-09-13 08:03:11 +00:00
TrackedFile CreateEmptyFile(string label = "");
TrackedFile GenerateFile(ByteSize size, string label = "");
void DeleteAllFiles();
void ScopedFiles(Action action);
T ScopedFiles<T>(Func<T> action);
2023-04-12 14:06:04 +00:00
}
public class FileManager : IFileManager
{
2023-06-07 07:59:00 +00:00
public const int ChunkSize = 1024 * 1024 * 100;
private static NumberSource folderNumberSource = new NumberSource(0);
2023-04-12 14:06:04 +00:00
private readonly Random random = new Random();
2023-09-12 08:31:55 +00:00
private readonly ILog log;
2023-09-21 08:33:09 +00:00
private readonly string rootFolder;
2023-04-12 14:06:04 +00:00
private readonly string folder;
2023-09-12 11:32:06 +00:00
private readonly List<List<TrackedFile>> fileSetStack = new List<List<TrackedFile>>();
2023-04-12 14:06:04 +00:00
2023-09-12 08:31:55 +00:00
public FileManager(ILog log, string rootFolder)
2023-04-12 14:06:04 +00:00
{
folder = Path.Combine(rootFolder, folderNumberSource.GetNextNumber().ToString("D5"));
2023-04-12 14:06:04 +00:00
this.log = log;
2023-09-21 08:33:09 +00:00
this.rootFolder = rootFolder;
2023-04-12 14:06:04 +00:00
}
2023-09-13 08:03:11 +00:00
public TrackedFile CreateEmptyFile(string label = "")
2023-04-12 14:06:04 +00:00
{
2023-09-21 08:33:09 +00:00
var path = Path.Combine(folder, Guid.NewGuid().ToString() + ".bin");
EnsureDirectory();
2023-09-12 11:32:06 +00:00
var result = new TrackedFile(log, path, label);
2023-04-12 14:06:04 +00:00
File.Create(result.Filename).Close();
if (fileSetStack.Any()) fileSetStack.Last().Add(result);
2023-04-12 14:06:04 +00:00
return result;
}
2023-09-13 08:03:11 +00:00
public TrackedFile GenerateFile(ByteSize size, string label)
2023-04-12 14:06:04 +00:00
{
2023-06-07 07:59:00 +00:00
var sw = Stopwatch.Begin(log);
2023-09-13 08:03:11 +00:00
var result = GenerateRandomFile(size, label);
2024-03-22 12:36:33 +00:00
sw.End($"Generated file {result.Describe()}.");
2023-04-12 14:06:04 +00:00
return result;
}
2023-09-13 08:03:11 +00:00
public void DeleteAllFiles()
2023-04-12 14:06:04 +00:00
{
DeleteDirectory();
2023-04-12 14:06:04 +00:00
}
public void ScopedFiles(Action action)
{
PushFileSet();
action();
PopFileSet();
}
public T ScopedFiles<T>(Func<T> action)
{
PushFileSet();
var result = action();
PopFileSet();
return result;
}
private void PushFileSet()
{
2023-09-12 11:32:06 +00:00
fileSetStack.Add(new List<TrackedFile>());
}
private void PopFileSet()
{
if (!fileSetStack.Any()) return;
var pop = fileSetStack.Last();
fileSetStack.Remove(pop);
foreach (var file in pop)
{
2023-09-21 08:33:09 +00:00
File.Delete(file.Filename);
}
2023-09-21 08:33:09 +00:00
// If the folder is now empty, delete it too.
if (!Directory.GetFiles(folder).Any()) DeleteDirectory();
}
2023-09-13 08:03:11 +00:00
private TrackedFile GenerateRandomFile(ByteSize size, string label)
2023-06-07 07:59:00 +00:00
{
2023-09-13 08:03:11 +00:00
var result = CreateEmptyFile(label);
2023-06-07 07:59:00 +00:00
CheckSpaceAvailable(result, size);
GenerateFileBytes(result, size);
return result;
}
2023-09-12 11:32:06 +00:00
private void CheckSpaceAvailable(TrackedFile testFile, ByteSize size)
2023-06-07 07:59:00 +00:00
{
var file = new FileInfo(testFile.Filename);
var drive = new DriveInfo(file.Directory!.Root.FullName);
var spaceAvailable = drive.TotalFreeSpace;
if (spaceAvailable < size.SizeInBytes)
{
2023-09-20 08:51:47 +00:00
var msg = $"Not enough disk space. " +
2023-06-07 07:59:00 +00:00
$"{Formatter.FormatByteSize(size.SizeInBytes)} required. " +
$"{Formatter.FormatByteSize(spaceAvailable)} available.";
log.Log(msg);
2023-09-20 08:51:47 +00:00
throw new Exception(msg);
2023-06-07 07:59:00 +00:00
}
}
2023-09-12 11:32:06 +00:00
private void GenerateFileBytes(TrackedFile result, ByteSize size)
2023-04-12 14:06:04 +00:00
{
long bytesLeft = size.SizeInBytes;
2023-06-07 07:59:00 +00:00
int chunkSize = ChunkSize;
2023-04-12 14:06:04 +00:00
while (bytesLeft > 0)
{
2023-06-07 07:59:00 +00:00
try
{
var length = Math.Min(bytesLeft, chunkSize);
AppendRandomBytesToFile(result, length);
bytesLeft -= length;
}
catch
{
chunkSize = chunkSize / 2;
if (chunkSize < 1024) throw;
}
2023-04-12 14:06:04 +00:00
}
}
2023-09-12 11:32:06 +00:00
private void AppendRandomBytesToFile(TrackedFile result, long length)
2023-04-12 14:06:04 +00:00
{
var bytes = new byte[length];
random.NextBytes(bytes);
using var stream = new FileStream(result.Filename, FileMode.Append);
stream.Write(bytes, 0, bytes.Length);
}
private void EnsureDirectory()
{
2023-09-21 08:33:09 +00:00
Directory.CreateDirectory(folder);
}
private void DeleteDirectory()
{
2023-09-21 08:33:09 +00:00
if (Directory.Exists(folder)) Directory.Delete(folder, true);
}
2023-04-12 14:06:04 +00:00
}
}