using ApplicationServices;
using AssertionHelper;
using DataLayer;
using LibationFileManager;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.IO;
namespace SearchIndexUpdateGuardTests;
///
/// A library change is committed to the database before the search index is updated, so a failure to update that
/// index must be reported rather than propagated. Letting it escape reported a successful scan as
/// "Error importing library" and starved the event's remaining subscribers.
///
[TestClass]
[DoNotParallelize]
public class SearchIndexUpdateGuardTests
{
private string tempLibationFiles = string.Empty;
private readonly List reportedFailures = [];
[TestInitialize]
public void Initialize()
{
tempLibationFiles = Path.Combine(Path.GetTempPath(), $"libation-search-index-guard-tests-{Guid.NewGuid():N}");
Directory.CreateDirectory(tempLibationFiles);
// A fresh Configuration resolves LibationFiles from this variable, so the index lands in the temp dir.
Environment.SetEnvironmentVariable(LibationFiles.LIBATION_FILES_DIR, tempLibationFiles);
Configuration.CreateMockInstance();
SearchEngineCommands.UpdateFailed += recordFailure;
}
[TestCleanup]
public void Cleanup()
{
SearchEngineCommands.UpdateFailed -= recordFailure;
Configuration.RestoreSingletonInstance();
Environment.SetEnvironmentVariable(LibationFiles.LIBATION_FILES_DIR, null);
try
{
Directory.Delete(tempLibationFiles, recursive: true);
}
catch (IOException)
{
// a leftover temp directory is not worth failing a test over
}
}
private void recordFailure(object? sender, Exception ex) => reportedFailures.Add(ex);
/// Occupying the SearchEngine path with a file leaves the engine nowhere to build its index.
private void blockTheIndexDirectory()
=> File.WriteAllText(Path.Combine(tempLibationFiles, "SearchEngine"), "not a directory");
private static List library()
{
var contributor = Contributor.GetEmpty();
var book = new Book(new AudibleProductId("B0TEST0001"), "Hound of the Baskervilles", null, null, 1, ContentType.Product, [contributor], [contributor], "us");
return [new LibraryBook(book, new DateTime(2026, 8, 15), "account")];
}
[TestMethod]
public void a_library_size_change_survives_an_unusable_search_index()
{
blockTheIndexDirectory();
SearchEngineCommands.OnLibrarySizeChanged(library());
reportedFailures.Should().HaveCount(1);
}
[TestMethod]
public void a_book_detail_change_survives_an_unusable_search_index()
{
blockTheIndexDirectory();
SearchEngineCommands.OnBookUserDefinedItemCommitted(library());
reportedFailures.Should().HaveCount(1);
}
[TestMethod]
public void a_successful_update_reports_no_failure()
{
SearchEngineCommands.OnLibrarySizeChanged(library());
reportedFailures.Should().HaveCount(0);
Directory.Exists(Path.Combine(tempLibationFiles, "SearchEngine")).Should().BeTrue();
}
}