namespace ZB.MOM.WW.MxGateway.IntegrationTests;
public sealed class IntegrationTestEnvironmentTests
{
/// Verifies that live MXAccess tests use correct environment variable name.
[Fact]
public void LiveMxAccessTests_AreOptInByEnvironmentVariable()
{
Assert.Equal(
"MXGATEWAY_RUN_LIVE_MXACCESS_TESTS",
IntegrationTestEnvironment.LiveMxAccessVariableName);
}
/// Verifies that worker executable uses correct environment variable name.
[Fact]
public void LiveMxAccessWorkerExecutable_UsesDocumentedEnvironmentVariable()
{
Assert.Equal(
"MXGATEWAY_LIVE_MXACCESS_WORKER_EXE",
IntegrationTestEnvironment.LiveMxAccessWorkerExecutableVariableName);
}
/// Verifies that repository root resolution accepts git worktree files.
[Fact]
public void ResolveRepositoryRoot_AcceptsGitWorktreeFile()
{
string temporaryRoot = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
string nestedDirectory = Path.Combine(temporaryRoot, "tests", "bin");
try
{
Directory.CreateDirectory(nestedDirectory);
Directory.CreateDirectory(Path.Combine(temporaryRoot, "src"));
File.WriteAllText(Path.Combine(temporaryRoot, ".git"), "gitdir: ../.git/worktrees/test");
// Pass temporaryRoot as the stop-boundary so the walker can never leak
// into ambient ancestors of Path.GetTempPath() (IntegrationTests-025).
string repositoryRoot = IntegrationTestEnvironment.ResolveRepositoryRoot(
nestedDirectory,
stopBoundary: temporaryRoot);
Assert.Equal(temporaryRoot, repositoryRoot);
}
finally
{
if (Directory.Exists(temporaryRoot))
{
Directory.Delete(temporaryRoot, recursive: true);
}
}
}
///
/// Verifies that
/// throws with a diagnostic message when
/// the walk exhausts without finding a repository root. The previous silent
/// fallback to Directory.GetCurrentDirectory() masked misconfiguration
/// (IntegrationTests-022); operators get a clear, actionable failure instead.
/// The stopBoundary isolates the walker from ambient ancestors of
/// (a redirected TMP, a co-located checkout
/// at C:\src, etc.) that could otherwise satisfy
/// IsRepositoryRoot and make this assertion flake on contributor or CI
/// boxes — see IntegrationTests-025.
///
[Fact]
public void ResolveRepositoryRoot_NoMarkers_ThrowsInvalidOperationExceptionNamingStartAndMarkers()
{
string isolatedRoot = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
string isolatedStart = Path.Combine(isolatedRoot, "nested");
try
{
Directory.CreateDirectory(isolatedStart);
InvalidOperationException ex = Assert.Throws(
() => IntegrationTestEnvironment.ResolveRepositoryRoot(
isolatedStart,
stopBoundary: isolatedRoot));
Assert.Contains(isolatedStart, ex.Message, StringComparison.Ordinal);
Assert.Contains(".git", ex.Message, StringComparison.Ordinal);
Assert.Contains(".sln", ex.Message, StringComparison.Ordinal);
Assert.Contains(
IntegrationTestEnvironment.LiveMxAccessWorkerExecutableVariableName,
ex.Message,
StringComparison.Ordinal);
}
finally
{
if (Directory.Exists(isolatedRoot))
{
Directory.Delete(isolatedRoot, recursive: true);
}
}
}
///
/// Verifies the stopBoundary parameter on
/// isolates the
/// walker from ambient ancestors that happen to satisfy IsRepositoryRoot
/// — the precise failure mode IntegrationTests-025 describes. The test
/// deliberately constructs an outer directory that *does* carry repository-root
/// markers (src/ + .git) and an inner isolated chain that does
/// not. Without the boundary the walker would happily stop at the outer
/// directory; with the boundary it must throw because the chain it can see
/// carries no markers. A future refactor that dropped or mis-honored the
/// boundary would surface here as a failed assertion instead of a silent flake
/// in CI.
///
[Fact]
public void ResolveRepositoryRoot_StopBoundary_IsolatesWalkerFromAmbientAncestorMarkers()
{
string outerRoot = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
string innerBoundary = Path.Combine(outerRoot, "inner");
string isolatedStart = Path.Combine(innerBoundary, "nested");
try
{
// Outer directory satisfies IsRepositoryRoot — it is the "ambient
// ancestor" the production walker would otherwise stop at.
Directory.CreateDirectory(Path.Combine(outerRoot, "src"));
File.WriteAllText(Path.Combine(outerRoot, ".git"), "gitdir: ../.git/worktrees/test");
// Inner chain carries no markers. The boundary sits between the inner
// chain and the outer marker-bearing ancestor.
Directory.CreateDirectory(isolatedStart);
// Sanity: without the boundary the production walker reaches outerRoot
// and silently returns it — the exact ambient-ancestor leak.
string leakedRoot = IntegrationTestEnvironment.ResolveRepositoryRoot(isolatedStart);
Assert.Equal(outerRoot, leakedRoot);
// With the boundary the walker is sealed inside the inner chain and
// must throw — the marker on outerRoot is invisible to it.
InvalidOperationException ex = Assert.Throws(
() => IntegrationTestEnvironment.ResolveRepositoryRoot(
isolatedStart,
stopBoundary: innerBoundary));
Assert.Contains(isolatedStart, ex.Message, StringComparison.Ordinal);
}
finally
{
if (Directory.Exists(outerRoot))
{
Directory.Delete(outerRoot, recursive: true);
}
}
}
}