Skip to content

Commit 11ee938

Browse files
committed
Merge remote-tracking branch 'origin/main' into fix-issue1708-1709-1710
2 parents a88d7c1 + 4df3cc1 commit 11ee938

19 files changed

Lines changed: 640 additions & 3 deletions

.github/workflows/dotnet.yml

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,41 @@ jobs:
182182
run: dotnet build tests/CodeIndex.Tests/CodeIndex.Tests.csproj --configuration Release --framework ${{ matrix.test-framework }} --no-restore
183183

184184
- name: Test
185-
run: dotnet test tests/CodeIndex.Tests/CodeIndex.Tests.csproj --configuration Release --framework ${{ matrix.test-framework }} --no-build --nologo --logger "trx;LogFileName=test_results.trx" --results-directory ./TestResults
185+
shell: pwsh
186+
run: |
187+
$testArgs = @(
188+
"test",
189+
"tests/CodeIndex.Tests/CodeIndex.Tests.csproj",
190+
"--configuration", "Release",
191+
"--framework", "${{ matrix.test-framework }}",
192+
"--no-build",
193+
"--nologo",
194+
"--settings", "tests/CodeIndex.Tests/CodeIndex.Tests.runsettings",
195+
"--blame-crash",
196+
"--blame-hang",
197+
"--blame-hang-timeout", "5m",
198+
"--logger", "trx;LogFileName=test_results.trx",
199+
"--results-directory", "./TestResults"
200+
)
201+
202+
dotnet @testArgs
203+
$firstExitCode = $LASTEXITCODE
204+
if ($firstExitCode -eq 0) {
205+
exit 0
206+
}
207+
208+
Write-Warning "Initial test run failed with exit code $firstExitCode. Rerunning once to classify possible flakiness."
209+
dotnet @testArgs
210+
$retryExitCode = $LASTEXITCODE
211+
if ($retryExitCode -eq 0) {
212+
New-Item -ItemType Directory -Force -Path ./TestResults | Out-Null
213+
"Initial test run failed, but the single retry passed. Treat this run as flaky and inspect TRX/blame artifacts." |
214+
Set-Content -Encoding UTF8 ./TestResults/flaky-retry.txt
215+
Write-Warning "Tests passed on retry; uploaded TestResults include flaky-retry.txt."
216+
exit 0
217+
}
218+
219+
exit $retryExitCode
186220
187221
- name: Summarize TRX telemetry
188222
if: always()
@@ -194,7 +228,14 @@ jobs:
194228
with:
195229
name: TestResults-${{ matrix.os }}-${{ matrix.test-framework }}
196230
if-no-files-found: warn
197-
path: TestResults/**/*.trx
231+
path: |
232+
TestResults/**/*.trx
233+
TestResults/**/*.txt
234+
TestResults/**/*.xml
235+
TestResults/**/*.dmp
236+
TestResults/**/*.dump
237+
TestResults/**/*Sequence*.xml
238+
TestResults/**/*.hangdump
198239
199240
- name: Publish
200241
if: matrix.os == 'ubuntu-latest' && matrix.test-framework == 'net8.0'

DEVELOPER_GUIDE.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
```bash
88
dotnet build
99
dotnet test
10+
dotnet test tests/CodeIndex.Tests/CodeIndex.Tests.csproj --settings tests/CodeIndex.Tests/CodeIndex.Tests.runsettings --blame-crash --blame-hang --blame-hang-timeout 5m
1011
dotnet run --project src/CodeIndex -- <command> [options]
1112
```
1213

@@ -32,7 +33,11 @@ multi-targets `net8.0;net9.0`, and CI runs the test suite on both frameworks
3233
across Linux, Windows, and macOS. Use a .NET SDK that can restore and run both
3334
target frameworks when validating the full CI-equivalent test matrix.
3435

35-
For test suite structure, shared helpers, and test-writing conventions, see [TESTING_GUIDE.md](TESTING_GUIDE.md).
36+
CI uses `tests/CodeIndex.Tests/CodeIndex.Tests.runsettings` plus VSTest blame
37+
crash/hang collection and a bounded one-time retry to distinguish repeatable
38+
failures from pass-on-retry flakes. For test suite structure, shared helpers,
39+
state-isolation rules, timeout diagnostics, and test-writing conventions, see
40+
[TESTING_GUIDE.md](TESTING_GUIDE.md).
3641

3742
## CI / Artifact Distribution
3843

TESTING_GUIDE.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ If you change test code, test helpers, test execution flow, or testing conventio
1111
```bash
1212
dotnet test
1313
dotnet test tests/CodeIndex.Tests/CodeIndex.Tests.csproj
14+
dotnet test tests/CodeIndex.Tests/CodeIndex.Tests.csproj --settings tests/CodeIndex.Tests/CodeIndex.Tests.runsettings --blame-crash --blame-hang --blame-hang-timeout 5m
1415
dotnet test --filter "FullyQualifiedName~GitHelperTests"
1516
```
1617

@@ -25,6 +26,7 @@ Use the full suite by default. Use targeted filters only while iterating locally
2526
- These test-only packages are separate from the production dependency rule in `src/CodeIndex`, which still allows only `Microsoft.Data.Sqlite` at runtime.
2627
- `FsCheck.Xunit` is reserved for property-based tests that assert universal invariants (never-throws contracts, idempotence, "output is parseable by downstream consumer") across randomly generated inputs. Use it to complement, not replace, the example-based `[Fact]` / `[Theory]` tests — pick FsCheck when the property is a universally quantified claim, and an example test when a specific concrete case is the contract.
2728
- Test parallelism: enabled by default across independent test classes. Tests that touch process-global state such as SQLite pool resets, environment variables, or current-directory overrides must use an explicit non-parallel collection, and tests that swap `Console.Out` / `Console.Error` must lock on `TestConsoleLock.Gate`.
29+
- CI runs the test project through `tests/CodeIndex.Tests/CodeIndex.Tests.runsettings`, enables VSTest blame crash and hang collection, applies a 30-minute session timeout plus 60-second xUnit long-running diagnostics, and reruns the suite once after an initial failure. If the retry passes, CI uploads `TestResults/flaky-retry.txt` with the TRX and blame artifacts so the run is treated as suspect instead of silently trusted.
2830

2931
## Test Layout
3032

@@ -85,6 +87,16 @@ The test project mirrors the production areas closely.
8587
- When a production comment or error string is bilingual, preserve that expectation in tests where it matters.
8688
- If a behavior change is user-visible, update tests, `CHANGELOG.md`, and any affected docs together.
8789

90+
### Shared state and parallelism audit
91+
92+
Use the inventory below before adding or moving a test class:
93+
94+
- SQLite pool resets, direct `SqliteConnection.ClearAllPools()` calls, process current-directory changes, or process-global environment variable mutation: put the class in the `SQLite pool sensitive` non-parallel collection.
95+
- Environment variables: use `EnvironmentVariableScope.Capture(...)` so setup failures and assertion failures restore the original values through one cleanup path.
96+
- `Console.Out` or `Console.Error` replacement: lock `TestConsoleLock.Gate` around the whole capture/swap window.
97+
- Temporary repositories and files: create them through `TestProjectHelper` when practical, and do not depend on user-level git config.
98+
- Long-running or performance-oriented tests: keep them skipped by default or give them broad deterministic budgets; if CI reports them in xUnit long-running diagnostics, first check runner load before tightening thresholds.
99+
88100
## Shared Helpers
89101

90102
### `TestProjectHelper`
@@ -198,6 +210,7 @@ Check the following:
198210
```bash
199211
dotnet test
200212
dotnet test tests/CodeIndex.Tests/CodeIndex.Tests.csproj
213+
dotnet test tests/CodeIndex.Tests/CodeIndex.Tests.csproj --settings tests/CodeIndex.Tests/CodeIndex.Tests.runsettings --blame-crash --blame-hang --blame-hang-timeout 5m
201214
dotnet test --filter "FullyQualifiedName~GitHelperTests"
202215
```
203216

@@ -212,6 +225,7 @@ dotnet test --filter "FullyQualifiedName~GitHelperTests"
212225
- これらの test-only package は `src/CodeIndex` の本番依存ルールとは別であり、runtime 側は引き続き `Microsoft.Data.Sqlite` のみを許容する。
213226
- `FsCheck.Xunit` はランダム生成入力に対する普遍的不変条件(never-throws、idempotence、"出力が downstream consumer で parse 可能" 等)を表明する property-based テスト専用です。例ベースの `[Fact]` / `[Theory]` を置き換えるのではなく補完するもので、普遍量化された主張なら FsCheck、特定の具体ケースが契約なら例ベースという形で使い分けてください。
214227
- テスト並列実行: 独立したテストクラス間ではデフォルトで有効です。SQLite pool の解放、環境変数の変更、カレントディレクトリの上書きのような process-global 状態を触るテストは、明示的な non-parallel collection に入れてください。`Console.Out` / `Console.Error` を差し替えるテストは `TestConsoleLock.Gate` で lock してください。
228+
- CI は `tests/CodeIndex.Tests/CodeIndex.Tests.runsettings` 経由でテストプロジェクトを実行し、VSTest の blame crash / hang 収集、30分のセッションタイムアウト、60秒の xUnit long-running 診断を有効にします。初回失敗時は suite を1回だけ再実行し、再実行で成功した場合は TRX / blame artifact と一緒に `TestResults/flaky-retry.txt` を upload して、その実行を疑わしい flaky run として扱います。
215229

216230
## テスト構成
217231

@@ -271,6 +285,16 @@ dotnet test --filter "FullyQualifiedName~GitHelperTests"
271285
- 本番コードのコメントやエラー文字列が英日併記前提なら、重要な箇所ではその期待もテストに反映する。
272286
- ユーザーに見える挙動を変えたら、テストに加えて `CHANGELOG.md` と関連ドキュメントも同じ変更に含める。
273287

288+
### 共有状態と並列実行の監査
289+
290+
テストクラスを追加または移動する前に、次の一覧を確認してください。
291+
292+
- SQLite pool reset、`SqliteConnection.ClearAllPools()` の直接呼び出し、プロセスの current directory 変更、process-global な環境変数変更: クラスを non-parallel な `SQLite pool sensitive` collection に入れる。
293+
- 環境変数: `EnvironmentVariableScope.Capture(...)` を使い、setup failure や assertion failure でも単一の cleanup 経路で元の値に戻す。
294+
- `Console.Out` / `Console.Error` の差し替え: capture / swap 期間全体を `TestConsoleLock.Gate` で lock する。
295+
- 一時 repo / file: 可能な限り `TestProjectHelper` 経由で作り、user-level の git config に依存しない。
296+
- 長時間または performance 系テスト: デフォルト skip にするか、決定的で十分広い budget を与える。CI の xUnit long-running 診断に出た場合は、閾値を締める前に runner 負荷を確認する。
297+
274298
## 共通ヘルパー
275299

276300
### `TestProjectHelper`
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
category: fixed
3+
issues:
4+
- 1610
5+
affected:
6+
- .github/workflows/dotnet.yml
7+
- TESTING_GUIDE.md
8+
- DEVELOPER_GUIDE.md
9+
---
10+
11+
## English
12+
13+
- **CI flaky-test classification (#1610)** — Added a bounded one-time test retry in CI and a `flaky-retry.txt` artifact marker when the retry passes after an initial failure.
14+
15+
## 日本語
16+
17+
- **CI の flaky test 分類 (#1610)** — CI テストに1回限りの bounded retry を追加し、初回失敗後の再実行で成功した場合に `flaky-retry.txt` artifact marker を残すようにしました。
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
category: fixed
3+
issues:
4+
- 1612
5+
affected:
6+
- TESTING_GUIDE.md
7+
- DEVELOPER_GUIDE.md
8+
---
9+
10+
## English
11+
12+
- **Test parallelism audit guidance (#1612)** — Documented the shared-state inventory for test classes that need serialized execution or explicit cleanup guards.
13+
14+
## 日本語
15+
16+
- **テスト並列実行の監査ガイド (#1612)** — 直列実行または明示的な cleanup guard が必要なテストクラス向けに、共有状態の inventory を文書化しました。
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
category: added
3+
issues:
4+
- 1756
5+
affected:
6+
- src/CodeIndex/Indexer/Extensibility/ConfiguredSymbolExtractor.cs
7+
- src/CodeIndex/Indexer/Extensibility/ExtractorPluginRegistry.cs
8+
---
9+
10+
## English
11+
12+
- **Added YAML-backed custom symbol patterns (#1756)**`cdidx` now loads regex symbol extractors from `.cdidx/patterns/*.yaml` and `~/.config/cdidx/patterns/*.yaml` so lightweight language patterns can live outside the binary.
13+
14+
## 日本語
15+
16+
- **YAML ベースのカスタムシンボルパターンを追加しました (#1756)**`.cdidx/patterns/*.yaml``~/.config/cdidx/patterns/*.yaml` から regex symbol extractor を読み込めるようになり、軽量な言語パターンをバイナリ外に置けます。
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
category: added
3+
issues:
4+
- 1757
5+
affected:
6+
- src/CodeIndex/Indexer/Scanning/FileIndexer.cs
7+
- src/CodeIndex/Indexer/Scanning/LanguageMapOverrides.cs
8+
---
9+
10+
## English
11+
12+
- **Added per-user and per-workspace language-map overrides (#1757)** — extension aliases from `~/.config/cdidx/langmap.yaml` and `.cdidx-langmap.yaml` now override built-in language detection, including compound suffixes such as `.kts.in`.
13+
14+
## 日本語
15+
16+
- **ユーザー単位・workspace 単位の language-map override を追加しました (#1757)**`~/.config/cdidx/langmap.yaml``.cdidx-langmap.yaml` の拡張子 alias が組み込み言語判定を上書きし、`.kts.in` のような複合サフィックスにも対応します。
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
category: added
3+
issues:
4+
- 1759
5+
affected:
6+
- src/CodeIndex/Cli/ProgramRunner.cs
7+
---
8+
9+
## English
10+
11+
- **Added `cdidx test-extractor` (#1759)** — contributors can run symbol extraction for one file with `--language` and `--file`, emit JSON, and compare against an expected symbols fixture without building a full index.
12+
13+
## 日本語
14+
15+
- **`cdidx test-extractor` を追加しました (#1759)** — contributor は full index を作らず、`--language``--file` で単一ファイルの symbol extraction を実行し、JSON 出力や expected symbols fixture との比較ができます。
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
category: fixed
3+
issues:
4+
- 1821
5+
affected:
6+
- .github/workflows/dotnet.yml
7+
- tests/CodeIndex.Tests/CodeIndex.Tests.runsettings
8+
- TESTING_GUIDE.md
9+
- DEVELOPER_GUIDE.md
10+
---
11+
12+
## English
13+
14+
- **CI test timeout and blame diagnostics (#1821)** — Added test runsettings with a session timeout and xUnit long-running diagnostics, enabled VSTest crash/hang blame capture in CI, and uploaded blame artifacts with TRX results.
15+
16+
## 日本語
17+
18+
- **CI テストの timeout / blame 診断 (#1821)** — セッションタイムアウトと xUnit long-running 診断を含む test runsettings を追加し、CI で VSTest の crash/hang blame 収集を有効化して、TRX と一緒に blame artifact をアップロードするようにしました。
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using System.Text.RegularExpressions;
2+
using CodeIndex.Models;
3+
4+
namespace CodeIndex.Indexer.Extensibility;
5+
6+
internal sealed class ConfiguredSymbolExtractor(
7+
string language,
8+
IReadOnlyCollection<string> fileExtensions,
9+
IReadOnlyList<ConfiguredSymbolExtractor.PatternRule> patterns) : ISymbolExtractor
10+
{
11+
internal sealed record PatternRule(string Kind, Regex Regex);
12+
13+
public string Language { get; } = language;
14+
15+
public IReadOnlyCollection<string> FileExtensions { get; } = fileExtensions;
16+
17+
public IReadOnlyList<SymbolRecord> Extract(long fileId, string source, ExtractionContext context)
18+
{
19+
var symbols = new List<SymbolRecord>();
20+
var lineNumber = 0;
21+
foreach (var line in source.Replace("\r\n", "\n", StringComparison.Ordinal).Replace('\r', '\n').Split('\n'))
22+
{
23+
lineNumber++;
24+
foreach (var pattern in patterns)
25+
{
26+
var match = pattern.Regex.Match(line);
27+
if (!match.Success)
28+
continue;
29+
30+
var name = match.Groups["name"].Success ? match.Groups["name"].Value : match.Value.Trim();
31+
if (string.IsNullOrWhiteSpace(name))
32+
continue;
33+
34+
symbols.Add(new SymbolRecord
35+
{
36+
FileId = fileId,
37+
Kind = pattern.Kind,
38+
Name = name,
39+
Line = lineNumber,
40+
StartLine = lineNumber,
41+
EndLine = lineNumber,
42+
Signature = line.Trim(),
43+
});
44+
break;
45+
}
46+
}
47+
48+
return symbols;
49+
}
50+
}

0 commit comments

Comments
 (0)