ModernUO/Projects/UOContent.Tests/Tests/WorldSaves/ArchiveJournalTests.cs
Kamron Batman 9a25054809
test: remove trivial, duplicate and content-value tests (#2721)
## Summary
Many tests proved a specific change when it landed but don't need to run on every CI build forever. This removes **202 test methods and 9 files: 313 test cases, 2,247 → 1,934**. UOContent.Tests drops from about 14s to about 5s locally.

Removed:
- **Tautologies.** Asserting a constant, a constructor readback or a trivial getter, or testing BCL behavior.
- **Exact duplicates** of a surviving test on the same code path.
- **Obsolete regressions** whose failure can no longer be expressed.
- **Game-content values** shard owners customize (era drop rates, loot and skill tables, single-creature tuning). Each customization would otherwise force a test fix.

## How it was decided
1. Every test was classified, with a reason, by a per-shard sweep over all 287 test files.
2. Each proposed deletion was then checked by a second, adversarial reviewer against the surviving tests and the production code.
3. Anything that was the only coverage of a separate code path was **kept**, even where it looked like a duplicate. Examples: the unsigned `SpanReader`/`SpanWriter` methods, the at-location versus bounds enumerators, null-map enumerables, the security filters, archive-journal state transitions. About 130 proposed deletions were rejected this way.

Whole files removed:
- `FishingTests`, apart from 3 tests: the map-edge scan, serpent cleanup, and SOS chest consumption. The SOS test now stops at the first chest instead of measuring a catch rate. The multi-million-cast rate simulations are gone.
- `LordOaksTests` and `MeerEnragedTests` (single-creature tests).
- `AutoArchiveHelperTests`, `JsonDiscoverableTypeAttributeTests`, `DecimalSerializationTests` and `EnumConversionTests` (tautologies, or tests of their own local helpers).
- `NetworkStatsTests`.
- `MigratedDataLoadTests` (a subset of `AllSpawnFilesLoadTests`).
- `SpawnerFixtureCapture`: a capture tool, not a test, and its `version == 12` assert can no longer pass. The `.bin` fixtures it produced stay.

## Tests
- Server.Tests: 811 pass.
- UOContent.Tests: 1,123 pass.

A follow-up PR, stacked on this one, fixes how the remaining tests behave: shared state, CI-vacuous tests, harness duplication.
2026-10-18 20:08:19 -07:00

218 lines
6.6 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using Server.Saves;
using Xunit;
namespace Server.Tests;
[Collection("Sequential UOContent Tests")]
public class ArchiveJournalTests : IDisposable
{
private readonly string _testDir;
public ArchiveJournalTests()
{
_testDir = Path.Combine(Path.GetTempPath(), $"modernuo-journal-test-{Guid.NewGuid():N}");
Directory.CreateDirectory(_testDir);
}
public void Dispose()
{
if (Directory.Exists(_testDir))
{
Directory.Delete(_testDir, true);
}
}
[Fact]
public void BeginOperation_CreatesStartedEntry()
{
// Arrange
ArchiveJournal.Configure(_testDir);
// Act
var entry = ArchiveJournal.BeginOperation(
ArchivePeriod.Hourly,
new DateTime(2026, 3, 22, 14, 0, 0, DateTimeKind.Utc),
"/tmp/archive.tar.zst.tmp",
"/archives/hourly/2026-03-22-14.tar.zst",
["backup1", "backup2"]
);
// Assert
Assert.Equal(ArchiveOperationState.Started, entry.State);
Assert.Equal(ArchivePeriod.Hourly, entry.Period);
Assert.Equal("/tmp/archive.tar.zst.tmp", entry.TempFile);
Assert.Equal(2, entry.SourceDirectories.Count);
Assert.Contains(entry, ArchiveJournal.Operations);
}
[Fact]
public void RecordArchived_TransitionsState()
{
// Arrange
ArchiveJournal.Configure(_testDir);
var entry = ArchiveJournal.BeginOperation(
ArchivePeriod.Daily,
new DateTime(2026, 3, 22, 0, 0, 0, DateTimeKind.Utc),
"/tmp/test.tmp",
"/archives/daily/2026-03-22.tar.zst",
["backup1"]
);
// Act
ArchiveJournal.RecordArchived(entry, 42, 1024000);
// Assert
Assert.Equal(ArchiveOperationState.Archived, entry.State);
Assert.Equal(42, entry.EntryCount);
Assert.Equal(1024000, entry.ArchiveBytes);
Assert.Null(entry.TempFile); // Temp file cleared after rename
}
[Fact]
public void RecordDistributed_StoresResults()
{
// Arrange
ArchiveJournal.Configure(_testDir);
var entry = ArchiveJournal.BeginOperation(
ArchivePeriod.Monthly,
new DateTime(2026, 3, 1, 0, 0, 0, DateTimeKind.Utc),
"/tmp/test.tmp",
"/archives/monthly/2026-03.tar.zst",
["backup1"]
);
ArchiveJournal.RecordArchived(entry, 100, 5000000);
var results = new Dictionary<string, bool>
{
{ "Local Filesystem", true },
{ "S3 us-east-1", false }
};
// Act
ArchiveJournal.RecordDistributed(entry, results);
// Assert
Assert.Equal(ArchiveOperationState.Distributed, entry.State);
Assert.True(entry.DestinationResults["Local Filesystem"]);
Assert.False(entry.DestinationResults["S3 us-east-1"]);
}
[Fact]
public void RecordCompleted_IsTerminal()
{
// Arrange
ArchiveJournal.Configure(_testDir);
var entry = ArchiveJournal.BeginOperation(
ArchivePeriod.Hourly,
new DateTime(2026, 3, 22, 14, 0, 0, DateTimeKind.Utc),
"/tmp/test.tmp",
"/archives/hourly/test.tar.zst",
["backup1"]
);
ArchiveJournal.RecordArchived(entry, 10, 500);
ArchiveJournal.RecordDistributed(entry, new Dictionary<string, bool>());
// Act
ArchiveJournal.RecordCompleted(entry);
// Assert
Assert.Equal(ArchiveOperationState.Completed, entry.State);
Assert.NotEqual(DateTime.MaxValue, entry.CompletedAt);
}
[Fact]
public void RecordFailure_RecordsReason()
{
// Arrange
ArchiveJournal.Configure(_testDir);
var entry = ArchiveJournal.BeginOperation(
ArchivePeriod.Hourly,
new DateTime(2026, 3, 22, 14, 0, 0, DateTimeKind.Utc),
"/tmp/test.tmp",
"/archives/hourly/test.tar.zst",
["backup1"]
);
// Act
ArchiveJournal.RecordFailure(entry, "Disk full");
// Assert
Assert.Equal(ArchiveOperationState.Failed, entry.State);
Assert.Equal("Disk full", entry.FailureReason);
Assert.NotEqual(DateTime.MaxValue, entry.CompletedAt);
}
[Fact]
public void Journal_PersistsToJsonFile()
{
// Arrange
ArchiveJournal.Configure(_testDir);
ArchiveJournal.BeginOperation(
ArchivePeriod.Hourly,
new DateTime(2026, 3, 22, 14, 0, 0, DateTimeKind.Utc),
"/tmp/test.tmp",
"/archives/hourly/test.tar.zst",
["backup1"]
);
// Assert - journal file should exist
var journalPath = Path.Combine(_testDir, ".archive-journal.json");
Assert.True(File.Exists(journalPath));
var content = File.ReadAllText(journalPath);
Assert.Contains("Hourly", content);
Assert.Contains("Started", content);
}
[Fact]
public void RecoverInterrupted_CleansUpStartedOperations()
{
// Arrange
ArchiveJournal.Configure(_testDir);
// Create a temp file that simulates an interrupted archive
var tempFile = Path.Combine(_testDir, "interrupted.tar.zst.tmp");
File.WriteAllText(tempFile, "partial archive data");
var entry = ArchiveJournal.BeginOperation(
ArchivePeriod.Hourly,
new DateTime(2026, 3, 22, 14, 0, 0, DateTimeKind.Utc),
tempFile,
Path.Combine(_testDir, "final.tar.zst"),
["backup1"]
);
// Act
ArchiveJournal.RecoverInterrupted();
// Assert
Assert.Equal(ArchiveOperationState.Failed, entry.State);
Assert.Equal("Interrupted during archive creation", entry.FailureReason);
Assert.False(File.Exists(tempFile)); // Temp file should be cleaned up
}
[Fact]
public void RecoverInterrupted_CompletesDistributedOperations()
{
// Arrange
ArchiveJournal.Configure(_testDir);
var entry = ArchiveJournal.BeginOperation(
ArchivePeriod.Daily,
new DateTime(2026, 3, 22, 0, 0, 0, DateTimeKind.Utc),
"/tmp/test.tmp",
"/archives/daily/test.tar.zst",
["backup1"]
);
ArchiveJournal.RecordArchived(entry, 50, 2000);
ArchiveJournal.RecordDistributed(entry, new Dictionary<string, bool> { { "Local", true } });
// Act - simulate restart
ArchiveJournal.RecoverInterrupted();
// Assert - should be marked completed
Assert.Equal(ArchiveOperationState.Completed, entry.State);
}
}