Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions TESTING_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ For boundary tests, use the smallest fixture that still crosses the boundary. If

- Never assume global git identity exists.
- Configure repo-local `user.name` and `user.email` inside the test setup.
- Disable repo-local commit/tag signing for fixture repositories so global signing settings cannot prompt or fail non-interactively.
- Use helper methods or `ProcessStartInfo.ArgumentList`; do not depend on shell-specific quoting behavior.

### Database tests
Expand Down Expand Up @@ -366,6 +367,7 @@ dotnet test --filter "FullyQualifiedName~GitHelperTests"

- global の git identity がある前提にしない。
- テストセットアップ内で repo-local の `user.name` と `user.email` を設定する。
- fixture リポジトリでは repo-local の commit/tag signing を無効化し、global signing 設定が非対話実行でプロンプトや失敗を起こさないようにする。
- shell 依存の quoting ではなく、ヘルパーや `ProcessStartInfo.ArgumentList` を使う。

### DB 系テスト
Expand Down
19 changes: 19 additions & 0 deletions changelog.d/unreleased/2729.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
category: fixed
issues:
- 2729
affected:
- tests/CodeIndex.Tests/TestProjectHelper.cs
- tests/CodeIndex.Tests/GitHelperTests.cs
- tests/CodeIndex.Tests/IndexCommandRunnerTests.cs
- tests/CodeIndex.Tests/GitTestProjectHelperTests.cs
- TESTING_GUIDE.md
---

## English

- **Git-backed test fixtures no longer inherit commit signing (#2729)** — temporary repositories created by test helpers now disable commit and tag signing locally so fixture commits do not prompt for signing-key passphrases.

## 日本語

- **Git を使うテスト fixture が commit signing を引き継がなくなりました (#2729)** — テストヘルパーが作る一時リポジトリでは commit / tag signing を repo-local に無効化し、fixture commit が署名キーのパスフレーズ入力を要求しないようにしました。
16 changes: 16 additions & 0 deletions changelog.d/unreleased/2730.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
category: fixed
issues:
- 2730
affected:
- src/CodeIndex/Cli/GlobalToolLog.cs
- tests/CodeIndex.Tests/GlobalToolLogTests.cs
---

## English

- **Persistent stderr mirroring no longer cascades disposed-writer failures (#2730)** — the global tool log tee now treats closed console/log writers as best-effort failures instead of throwing `ObjectDisposedException` back into test or CLI callers.

## 日本語

- **永続 stderr mirror が閉じた writer の失敗を連鎖させなくなりました (#2730)** — global tool log の tee は、閉じた console/log writer をベストエフォートの失敗として扱い、`ObjectDisposedException` をテストや CLI 呼び出し元へ投げ返さないようになりました。
29 changes: 21 additions & 8 deletions src/CodeIndex/Cli/GlobalToolLog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -638,26 +638,39 @@ private sealed class TeeTextWriter(TextWriter primary, TextWriter secondary) : T

public override void Flush()
{
primary.Flush();
secondary.Flush();
TryWrite(primary.Flush);
TryWrite(secondary.Flush);
}

public override void Write(char value)
{
primary.Write(value);
secondary.Write(value);
TryWrite(() => primary.Write(value));
TryWrite(() => secondary.Write(value));
}

public override void Write(string? value)
{
primary.Write(value);
secondary.Write(value);
TryWrite(() => primary.Write(value));
TryWrite(() => secondary.Write(value));
}

public override void WriteLine(string? value)
{
primary.WriteLine(value);
secondary.WriteLine(value);
TryWrite(() => primary.WriteLine(value));
TryWrite(() => secondary.WriteLine(value));
}

private static void TryWrite(Action write)
{
try
{
write();
}
catch (Exception ex) when (ex is IOException or ObjectDisposedException)
{
// Best-effort mirror: a disposed console writer must not cascade into callers.
// mirror はベストエフォート。閉じた console writer が呼び出し側へ波及しないようにする。
}
}
}
}
2 changes: 2 additions & 0 deletions tests/CodeIndex.Tests/GitHelperTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,8 @@ private string CreateGitRepo()
RunGit(repoDir, "init");
RunGit(repoDir, "config", "user.name", "CodeIndex Tests");
RunGit(repoDir, "config", "user.email", "tests@example.com");
RunGit(repoDir, "config", "commit.gpgsign", "false");
RunGit(repoDir, "config", "tag.gpgsign", "false");

return repoDir;
}
Expand Down
41 changes: 41 additions & 0 deletions tests/CodeIndex.Tests/GitTestProjectHelperTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
namespace CodeIndex.Tests;

public class GitTestProjectHelperTests
{
[Fact]
public void InitializeGitRepo_DisablesCommitSigningForFixtureCommits()
{
var projectRoot = TestProjectHelper.CreateTempProject("cdidx_git_signing");
var globalConfig = Path.Combine(projectRoot, "global-gitconfig");
try
{
File.WriteAllText(
globalConfig,
"""
[commit]
gpgsign = true
[gpg]
format = ssh
[user]
signingkey = /definitely/missing/signing-key
""");
using var env = EnvironmentVariableScope.Capture("GIT_CONFIG_GLOBAL");
env.Set("GIT_CONFIG_GLOBAL", globalConfig);

TestProjectHelper.InitializeGitRepo(projectRoot);
File.WriteAllText(Path.Combine(projectRoot, "app.cs"), "class App {}\n");

TestProjectHelper.RunGit(projectRoot, "add", "app.cs");
var commitSigning = TestProjectHelper.RunGit(projectRoot, "config", "--get", "commit.gpgsign").Trim();
var tagSigning = TestProjectHelper.RunGit(projectRoot, "config", "--get", "tag.gpgsign").Trim();
TestProjectHelper.RunGit(projectRoot, "commit", "-m", "fixture");

Assert.Equal("false", commitSigning);
Assert.Equal("false", tagSigning);
}
finally
{
TestProjectHelper.DeleteDirectory(projectRoot);
}
}
}
47 changes: 47 additions & 0 deletions tests/CodeIndex.Tests/GlobalToolLogTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;
using CodeIndex.Cli;

Expand Down Expand Up @@ -117,6 +118,52 @@ public void TryStart_WritesInvariantUtcTimestampAndStackTrace()
}
}

[Fact]
public void TryStart_ErrorMirrorIgnoresDisposedOriginalConsoleWriter()
{
var logRoot = Path.Combine(Path.GetTempPath(), $"cdidx_global_log_disposed_{Guid.NewGuid():N}");
var originalError = Console.Error;
try
{
using var env = EnvironmentVariableScope.Capture(
"CDIDX_FORCE_GLOBAL_TOOL_LOG",
"CDIDX_DISABLE_PERSISTENT_LOG",
"CDIDX_GLOBAL_TOOL_LOG_DIR");
env.Set("CDIDX_FORCE_GLOBAL_TOOL_LOG", "1");
env.Set("CDIDX_DISABLE_PERSISTENT_LOG", null);
env.Set("CDIDX_GLOBAL_TOOL_LOG_DIR", logRoot);

using var session = GlobalToolLog.TryStartForTesting(
["status"],
"test",
afterWriterCreated: () => Console.SetError(new ThrowingTextWriter()));

var exception = Record.Exception(() => Console.Error.WriteLine("mirrored error"));

Assert.NotNull(session);
Assert.Null(exception);
}
finally
{
Console.SetError(originalError);
if (Directory.Exists(logRoot))
Directory.Delete(logRoot, recursive: true);
}
}

private static void ThrowForGlobalToolLogTest() =>
throw new InvalidOperationException("global log stack trace test");

private sealed class ThrowingTextWriter : TextWriter
{
public override Encoding Encoding => Encoding.UTF8;

public override void Flush() => throw new ObjectDisposedException(nameof(ThrowingTextWriter));

public override void Write(char value) => throw new ObjectDisposedException(nameof(ThrowingTextWriter));

public override void Write(string? value) => throw new ObjectDisposedException(nameof(ThrowingTextWriter));

public override void WriteLine(string? value) => throw new ObjectDisposedException(nameof(ThrowingTextWriter));
}
}
2 changes: 2 additions & 0 deletions tests/CodeIndex.Tests/IndexCommandRunnerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8844,6 +8844,8 @@ private static void RunGit(string workDir, params string[] args)
{
RunGit(workDir, "config", "user.name", "CodeIndex Tests");
RunGit(workDir, "config", "user.email", "tests@codeindex.local");
RunGit(workDir, "config", "commit.gpgsign", "false");
RunGit(workDir, "config", "tag.gpgsign", "false");
}
}

Expand Down
2 changes: 2 additions & 0 deletions tests/CodeIndex.Tests/TestProjectHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ internal static void InitializeGitRepo(string projectRoot)
RunGit(projectRoot, "init");
RunGit(projectRoot, "config", "user.name", "CodeIndex Tests");
RunGit(projectRoot, "config", "user.email", "tests@codeindex.local");
RunGit(projectRoot, "config", "commit.gpgsign", "false");
RunGit(projectRoot, "config", "tag.gpgsign", "false");

var excludePath = Path.Combine(projectRoot, ".git", "info", "exclude");
Directory.CreateDirectory(Path.GetDirectoryName(excludePath)!);
Expand Down
Loading