mirror of
https://github.com/rmcrackan/Libation.git
synced 2026-09-13 06:07:30 -04:00
Path.GetPathRoot always returns "/" for absolute Unix paths, so bulk backup preflight queried composefs root free space (often 0 on Bazzite) instead of the filesystem containing Books/In progress. On Unix, symlink-canonicalize paths (so /home -> /var/home) and pick the longest DriveInfo.GetDrives() mount prefix. Route GetBackupDriveSpaces through the shared helper so grouping and free-space queries agree. Co-authored-by: rmcrackan <rmcrackan@gmail.com>
225 lines
7.2 KiB
C#
225 lines
7.2 KiB
C#
using LibationFileManager;
|
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
using System;
|
|
using System.IO;
|
|
using System.Linq;
|
|
|
|
namespace LibationFileManager.Tests;
|
|
|
|
[TestClass]
|
|
public class DiskSpaceHelperTests
|
|
{
|
|
[TestMethod]
|
|
public void IsDiskFullException_detects_message()
|
|
{
|
|
var ex = new IOException("There is not enough space on the disk. : 'C:\\temp\\x.aaxc'.");
|
|
Assert.IsTrue(DiskSpaceHelper.IsDiskFullException(ex));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void IsDiskFullException_detects_message_in_aggregate()
|
|
{
|
|
var inner = new IOException("Failed to create file because the disk was full.");
|
|
var ex = new AggregateException(inner);
|
|
Assert.IsTrue(DiskSpaceHelper.IsDiskFullException(ex));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void ErrorMessageIndicatesDiskFull_matches_common_phrases()
|
|
{
|
|
Assert.IsTrue(DiskSpaceHelper.ErrorMessageIndicatesDiskFull("There is not enough space on the disk. : 'C:\\temp\\x.aaxc'."));
|
|
Assert.IsTrue(DiskSpaceHelper.ErrorMessageIndicatesDiskFull("Write failed: disk quota has been exceeded."));
|
|
Assert.IsTrue(DiskSpaceHelper.ErrorMessageIndicatesDiskFull("No space left on device"));
|
|
Assert.IsFalse(DiskSpaceHelper.ErrorMessageIndicatesDiskFull("Unable to read beyond the end of the stream."));
|
|
}
|
|
|
|
[TestMethod]
|
|
[OSCondition(OperatingSystems.Windows)]
|
|
public void Windows_NormalizePathForDriveQuery_strips_extended_prefix()
|
|
{
|
|
Assert.AreEqual(@"C:\Audiobooks\Books", DiskSpaceHelper.NormalizePathForDriveQuery(@"\\?\C:\Audiobooks\Books"));
|
|
Assert.AreEqual(@"\\server\share\Books", DiskSpaceHelper.NormalizePathForDriveQuery(@"\\?\UNC\server\share\Books"));
|
|
}
|
|
|
|
[TestMethod]
|
|
[OSCondition(OperatingSystems.Windows)]
|
|
public void Windows_GetPathRootForDiskSpaceCheck_strips_extended_prefix()
|
|
{
|
|
Assert.AreEqual(@"C:\", DiskSpaceHelper.GetPathRootForDiskSpaceCheck(@"\\?\C:\Audiobooks\Books"));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void FindLongestMountPointPrefix_prefers_var_home_over_root()
|
|
{
|
|
var mounts = new[] { "/", "/boot", "/var/home", "/tmp" };
|
|
|
|
Assert.AreEqual(
|
|
"/var/home",
|
|
DiskSpaceHelper.FindLongestMountPointPrefix("/var/home/user/Libation/Books", mounts));
|
|
Assert.AreEqual(
|
|
"/var/home",
|
|
DiskSpaceHelper.FindLongestMountPointPrefix("/var/home", mounts));
|
|
Assert.AreEqual(
|
|
"/tmp",
|
|
DiskSpaceHelper.FindLongestMountPointPrefix("/tmp/Libation-user", mounts));
|
|
Assert.AreEqual(
|
|
"/",
|
|
DiskSpaceHelper.FindLongestMountPointPrefix("/usr/local/bin", mounts));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void FindLongestMountPointPrefix_does_not_match_partial_segment()
|
|
{
|
|
// "/var/home2/..." must not match mount "/var/home"
|
|
var mounts = new[] { "/", "/var/home" };
|
|
|
|
Assert.AreEqual(
|
|
"/",
|
|
DiskSpaceHelper.FindLongestMountPointPrefix("/var/home2/books", mounts));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void FindLongestMountPointPrefix_home_without_symlink_resolution_stays_on_root()
|
|
{
|
|
// Documents the Bazzite trap: /home/... does not prefix-match /var/home until symlinks are resolved.
|
|
var mounts = new[] { "/", "/var/home", "/tmp" };
|
|
|
|
Assert.AreEqual(
|
|
"/",
|
|
DiskSpaceHelper.FindLongestMountPointPrefix("/home/user/Libation/Books", mounts));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void ResolvePathSymlinks_follows_home_to_var_home_style_link()
|
|
{
|
|
if (OperatingSystem.IsWindows())
|
|
Assert.Inconclusive("Skipped because OS is Windows.");
|
|
|
|
var root = Path.Combine(Path.GetTempPath(), "libation-diskspace-" + Guid.NewGuid().ToString("N"));
|
|
var varHome = Path.Combine(root, "var", "home");
|
|
var homeLink = Path.Combine(root, "home");
|
|
var booksUnderHome = Path.Combine(homeLink, "user", "Libation", "Books");
|
|
|
|
try
|
|
{
|
|
Directory.CreateDirectory(varHome);
|
|
Directory.CreateSymbolicLink(homeLink, varHome);
|
|
|
|
var resolved = DiskSpaceHelper.ResolvePathSymlinks(booksUnderHome);
|
|
var expected = Path.Combine(varHome, "user", "Libation", "Books");
|
|
|
|
Assert.AreEqual(expected, resolved);
|
|
|
|
var mounts = new[] { "/", varHome, Path.Combine(root, "tmp") };
|
|
Assert.AreEqual(
|
|
varHome,
|
|
DiskSpaceHelper.FindLongestMountPointPrefix(resolved, mounts));
|
|
}
|
|
finally
|
|
{
|
|
try
|
|
{
|
|
if (Directory.Exists(root))
|
|
Directory.Delete(root, recursive: true);
|
|
}
|
|
catch
|
|
{
|
|
// best-effort cleanup
|
|
}
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public void GetPathRootForDiskSpaceCheck_unix_uses_real_mount_not_always_slash()
|
|
{
|
|
if (OperatingSystem.IsWindows())
|
|
Assert.Inconclusive("Skipped because OS is Windows.");
|
|
|
|
// Pick any ready non-root mount that exists on this machine (often /tmp or similar).
|
|
var nonRootMount = DriveInfo.GetDrives()
|
|
.Where(d => d.IsReady && d.Name is not "/" and not null)
|
|
.OrderByDescending(d => d.Name.Length)
|
|
.FirstOrDefault();
|
|
|
|
if (nonRootMount is null)
|
|
Assert.Inconclusive("No non-root mounts available to assert against.");
|
|
|
|
var probePath = Path.Combine(nonRootMount.Name.TrimEnd(Path.DirectorySeparatorChar), "libation-probe");
|
|
var root = DiskSpaceHelper.GetPathRootForDiskSpaceCheck(probePath);
|
|
|
|
Assert.AreEqual(nonRootMount.Name, root);
|
|
Assert.AreNotEqual("/", root);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void GetRequiredBytesForDriveUsage_uses_batch_for_books_only()
|
|
{
|
|
const int bookCount = 500;
|
|
var expected = bookCount * DiskSpaceHelper.EstimatedBytesPerAudiobookBackup;
|
|
|
|
Assert.AreEqual(expected, DiskSpaceHelper.GetRequiredBytesForDriveUsage(DiskSpaceHelper.BackupDriveUsage.Books, bookCount));
|
|
Assert.AreEqual(
|
|
expected,
|
|
DiskSpaceHelper.GetRequiredBytesForDriveUsage(DiskSpaceHelper.BackupDriveUsage.Books | DiskSpaceHelper.BackupDriveUsage.InProgress, bookCount));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void GetRequiredBytesForDriveUsage_uses_single_title_for_in_progress_only()
|
|
{
|
|
Assert.AreEqual(
|
|
DiskSpaceHelper.EstimatedBytesPerAudiobookBackup,
|
|
DiskSpaceHelper.GetRequiredBytesForDriveUsage(DiskSpaceHelper.BackupDriveUsage.InProgress, 500));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void GetCriticalFreeBytesForDriveUsage_in_progress_requires_one_title_plus_margin()
|
|
{
|
|
Assert.AreEqual(
|
|
DiskSpaceHelper.EstimatedBytesPerAudiobookBackup + DiskSpaceHelper.InProgressPreflightMarginBytes,
|
|
DiskSpaceHelper.GetCriticalFreeBytesForDriveUsage(DiskSpaceHelper.BackupDriveUsage.InProgress));
|
|
|
|
Assert.AreEqual(
|
|
DiskSpaceHelper.CriticalFreeBytes,
|
|
DiskSpaceHelper.GetCriticalFreeBytesForDriveUsage(DiskSpaceHelper.BackupDriveUsage.Books));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void HasSufficientSpaceForBulkBackup_in_progress_not_judged_by_batch_estimate()
|
|
{
|
|
var drives = new[]
|
|
{
|
|
new DiskSpaceHelper.BackupDriveSpace(
|
|
@"D:\",
|
|
[@"D:\Books"],
|
|
500L * 1024 * 1024 * 1024,
|
|
500L * DiskSpaceHelper.EstimatedBytesPerAudiobookBackup,
|
|
DiskSpaceHelper.BackupDriveUsage.Books),
|
|
new DiskSpaceHelper.BackupDriveSpace(
|
|
@"C:\",
|
|
[@"C:\Temp\Libation-user"],
|
|
600L * 1024 * 1024,
|
|
DiskSpaceHelper.EstimatedBytesPerAudiobookBackup,
|
|
DiskSpaceHelper.BackupDriveUsage.InProgress),
|
|
};
|
|
|
|
Assert.IsTrue(DiskSpaceHelper.HasSufficientSpaceForBulkBackup(drives));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void AnyDriveCriticallyLow_in_progress_uses_single_title_threshold()
|
|
{
|
|
var drives = new[]
|
|
{
|
|
new DiskSpaceHelper.BackupDriveSpace(
|
|
@"C:\",
|
|
[@"C:\Temp\Libation-user"],
|
|
200L * 1024 * 1024,
|
|
DiskSpaceHelper.EstimatedBytesPerAudiobookBackup,
|
|
DiskSpaceHelper.BackupDriveUsage.InProgress),
|
|
};
|
|
|
|
Assert.IsTrue(DiskSpaceHelper.AnyDriveCriticallyLow(drives));
|
|
Assert.IsFalse(DiskSpaceHelper.HasSufficientSpaceForBulkBackup(drives));
|
|
}
|
|
}
|