Files
LlamaCasty/ytLive.Tests/DiskHygieneTests.cs
T
gramps 1a6a549e17 feat(55): stop leaving disk debts — temp clips and a low-disk guard
595 green, 0 warnings. Completes TASK 55 (slice 1, log rotation, shipped 2026-10-22).

- **`AlertClipCleanup`**: the default alert clip is materialised into `%TEMP%` for ffmpeg to read, and
  nothing ever deleted it — one orphan per profile that ever played an alert. Now: delete this session's
  file in `Shutdown`, and sweep `ytLive-alert-*.mp4` at startup for anything a crash left behind. Only
  the prefix we own is touched; a directory is never deleted.
- **`DiskSpaceGuard`**: a recording that dies of a full disk is a trust breach, so the numbers are a
  pure policy — refuse to start under **1 GB** (toast; the stream still starts, recording does not),
  warn under **5 GB** at start ("about eighty minutes" at 8 Mbps ≈ 3.6 GB/h), and one mid-show warning
  under **2 GB** — the last useful moment before the encoder fails for a reason it won't explain.
  Unreadable drives (a USB stick that just left) return null and never block a running recording.

Tests are policy-level on purpose: filling a real drive is not a test. `DiskHygieneTests` proves the
sweep only removes our own files and that the thresholds behave at both ends.
2026-11-10 11:55:42 -08:00

71 lines
2.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.IO;
using Xunit;
using ytLive.Services;
namespace ytLive.Tests;
/// <summary>
/// TASK 55·2–3 — the two disk debts a free app must not leave: the temp alert clip it materialises and
/// never deletes, and a recording that starts with no room to finish.
///
/// <para>Both are tested as policy, because the alternative — filling a real drive — is not a test.</para>
/// </summary>
public sealed class DiskHygieneTests : IDisposable
{
private readonly string _dir = Path.Combine(Path.GetTempPath(), $"ytLlive-disk-{Guid.NewGuid():N}");
public DiskHygieneTests() => Directory.CreateDirectory(_dir);
public void Dispose()
{
try { Directory.Delete(_dir, recursive: true); } catch { /* best effort */ }
}
[Fact]
public void Sweep_RemovesOnlyTheClipsWeCreated()
{
var ours1 = Path.Combine(_dir, "ytLive-alert-abc.mp4");
var ours2 = Path.Combine(_dir, "ytLive-alert-def.mp4");
var theirs = Path.Combine(_dir, "someone-elses-recording.mp4");
File.WriteAllText(ours1, "x");
File.WriteAllText(ours2, "x");
File.WriteAllText(theirs, "x");
var removed = AlertClipCleanup.Sweep(_dir);
Assert.Equal(2, removed);
Assert.False(File.Exists(ours1));
Assert.False(File.Exists(ours2));
Assert.True(File.Exists(theirs)); // never touch anything that isn't ours
}
[Fact]
public void Delete_IsSafeOnMissingBlankAndNull()
{
Assert.False(AlertClipCleanup.Delete(null));
Assert.False(AlertClipCleanup.Delete(""));
Assert.False(AlertClipCleanup.Delete(Path.Combine(_dir, "not-there.mp4")));
var file = Path.Combine(_dir, "ytLive-alert-gone.mp4");
File.WriteAllText(file, "x");
Assert.True(AlertClipCleanup.Delete(file));
Assert.False(File.Exists(file));
}
[Fact]
public void RecordingIsRefusedBelowAGigabyte_WarnedBelowFive_AndQuietAbove()
{
Assert.Equal(DiskSpaceGuard.StartDecision.Block, DiskSpaceGuard.ForStart(500L * 1024 * 1024));
Assert.Equal(DiskSpaceGuard.StartDecision.Warn, DiskSpaceGuard.ForStart(2L * 1024 * 1024 * 1024));
Assert.Equal(DiskSpaceGuard.StartDecision.Ok, DiskSpaceGuard.ForStart(20L * 1024 * 1024 * 1024));
}
[Fact]
public void MidRecordingWarnsOnceBelowTwoGigabytes()
{
Assert.False(DiskSpaceGuard.ShouldWarnDuring(3L * 1024 * 1024 * 1024));
Assert.True(DiskSpaceGuard.ShouldWarnDuring(1L * 1024 * 1024 * 1024));
}
}