Files
Libation/Source/_Tests/LibationUiBase.Tests/SearchIndexRecoveryTests.cs
T
Cursor Agentandrmcrackan bb55fb40a3 Stop the filter box looping on dialogs when the search index is at fault
Both grids restored the last good filter by recursing into the filter handler, which
never terminated once the search index rather than the query was the problem: the
restore fails the same way, and the retry uses the same filter. The user got an
endless run of dialogs, each of them blaming a filter string that was fine. Only an
empty last-good filter broke the loop, because that short-circuits before reaching
the search engine.

The fallback is now a bounded sequence -- last good filter, then no filter -- and
the message distinguishes an index Libation cannot reach from a query it cannot
parse. Only the first failure is reported, so restoring is quiet. A malformed query
never surfaces as an IO-family exception, which QueryFailureShapeTests pins against
the real engine, so a typo is never mistaken for index trouble or made to trigger a
rebuild.

Co-authored-by: rmcrackan <rmcrackan@gmail.com>
2026-08-16 18:06:40 +00:00

50 lines
2.1 KiB
C#

using LibationUiBase;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers;
using Lucene.Net.Store;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
namespace LibationUiBase.Tests;
[TestClass]
public class SearchIndexRecoveryTests
{
[TestMethod]
public void instructions_name_the_folder_and_how_to_find_it()
{
StringAssert.Contains(SearchIndexRecovery.ManualRecoveryInstructions, "SearchEngine");
StringAssert.Contains(SearchIndexRecovery.ManualRecoveryInstructions, "Open log folder");
// the whole point of the guard is that the library survived
StringAssert.Contains(SearchIndexRecovery.ManualRecoveryInstructions, "library itself is fine");
}
/// <summary>
/// Every way of failing to reach the index. Reporting one of these as a bad filter string sends the user
/// looking for a typo in a query that was fine.
/// </summary>
[TestMethod]
public void failures_to_reach_the_index_are_told_apart_from_a_bad_query()
{
Assert.IsTrue(SearchIndexRecovery.IsIndexUnavailable(new IOException("read past EOF")));
Assert.IsTrue(SearchIndexRecovery.IsIndexUnavailable(new CorruptIndexException("checksum mismatch in segments file")));
Assert.IsTrue(SearchIndexRecovery.IsIndexUnavailable(new LockObtainFailedException("Lock obtain timed out")));
Assert.IsTrue(SearchIndexRecovery.IsIndexUnavailable(new UnauthorizedAccessException()));
// cloud-sync debris, which Lucene reports while parsing segments file names
Assert.IsTrue(SearchIndexRecovery.IsIndexUnavailable(new ArgumentException("Invalid or unsupported character in number: )")));
Assert.IsFalse(SearchIndexRecovery.IsIndexUnavailable(new ParseException("Cannot parse '[unclosed'")));
Assert.IsFalse(SearchIndexRecovery.IsIndexUnavailable(new ArgumentException("some other argument problem")));
}
/// <summary>A damaged index fails on every library change, and these steps only need following once.</summary>
[TestMethod]
public void the_user_is_told_once_per_session()
{
Assert.IsTrue(SearchIndexRecovery.ShouldNotify());
Assert.IsFalse(SearchIndexRecovery.ShouldNotify());
Assert.IsFalse(SearchIndexRecovery.ShouldNotify());
}
}