Conversation
Add pre-build environment setup section that detects when .dotnet contains binaries for the wrong OS and cleans .dotnet, .packages, and artifacts for a fresh bootstrap. Update all build/test commands to show both Linux/macOS and Windows equivalents with a quick-reference table. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…sification - Add PowerShell OS detection alongside bash - Add guidance for extracting OS-specific commands from tables - Add placeholder substitution and cross-platform adaptation rules - Use SQL tracking table instead of markdown table - Distinguish ENV_ISSUE from ERROR in result classification - Improve Fix or Flag section with actionable steps per status Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- eng/build.ps1: Forward exit code from Arcade build script using \�xit \0\ to ensure non-zero exit codes are propagated to the caller - eng/common/tools.ps1: Add diagnostic log message before exiting so the exit code is visible in build output - .github/skills/vstest-build-test/SKILL.md: Fix Windows test filter flag from \-p\ to \-projects\ since \-p\ is ambiguous in PowerShell and does not work as expected Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When multiple vstest processes run in parallel with the HTML logger, temporary XML result files could collide because the timestamp-based filename only has second-level precision, and the in-process lock doesn't prevent cross-process races. Changes: - Include process ID in the temp XML filename for cross-process uniqueness - Replace File.Exists + File.Create with atomic FileMode.CreateNew to handle any remaining race conditions gracefully via retry - Remove unused FileCreateLockObject (cross-process lock was ineffective) Fixes: #15404 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add build commands, test project mappings, repository structure, logger architecture notes, and analyzer pitfalls to copilot-instructions.md. Update vstest-build-test skill with logger-specific notes covering TRX and HTML logger architecture, test patterns, and common analyzer issues. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Fixes cross-process temp XML filename collisions in the HTML logger when multiple vstest.console instances run in parallel.
Changes:
- Adds PID to the temp XML filename and switches to
FileMode.CreateNewfor atomic “create if not exists”. - Adds a unit test to validate the PID is present in the generated XML path.
- Updates build/doc tooling and authoring docs for repo build/test guidance.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| test/Microsoft.TestPlatform.Extensions.HtmlLogger.UnitTests/HtmlLoggerTests.cs | Adds a unit test asserting PID is included in the temp XML filename. |
| src/Microsoft.TestPlatform.Extensions.HtmlLogger/HtmlLogger.cs | Adds PID to filename and uses FileMode.CreateNew for atomic file creation; removes ineffective in-proc lock. |
| eng/common/tools.ps1 | Adds an extra console message when exiting with an exit code. |
| eng/build.ps1 | Attempts to forward the exit code from the invoked Arcade build script. |
| .github/skills/vstest-build-test/SKILL.md | Adds repo-specific build/test instructions and logger notes. |
| .github/skills/validate-skills/SKILL.md | Adds a procedure for validating that documented skill commands work. |
| .github/skills/creating-skills/SKILL.md | Adds guidance for creating skill files and frontmatter. |
| .github/copilot-instructions.md | Adds build/test command guidance and repository structure notes. |
When multiple vstest processes run in parallel with the HTML logger, temporary XML result files could collide because the timestamp-based filename only has second-level precision, and the in-process lock doesn't prevent cross-process races. Changes: - Add millisecond precision to temp XML filename timestamp (HHmmss → HHmmssfff) to greatly reduce collision likelihood across parallel processes - Replace File.Exists + File.Create with atomic FileMode.CreateNew to handle any remaining race conditions gracefully via retry - Remove unused FileCreateLockObject (cross-process lock was ineffective) Fixes: #15404 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1d29994 to
3cb268d
Compare
|
needs merge of #15434 |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
| - **Temp XML naming:** `TestResult_{user}_{machine}_{timestamp}_{pid}.xml` — PID ensures cross-process uniqueness | ||
| - **File creation:** Uses `FileMode.CreateNew` for atomic creation with retry on collision |
There was a problem hiding this comment.
Same issue as in copilot-instructions.md: the documented filename pattern includes {pid} but the actual code does not add a PID to the filename. The uniqueness strategy relies on millisecond timestamps plus FileMode.CreateNew with retry. This documentation should be corrected to match the actual implementation.
| - **Temp XML naming:** `TestResult_{user}_{machine}_{timestamp}_{pid}.xml` — PID ensures cross-process uniqueness | |
| - **File creation:** Uses `FileMode.CreateNew` for atomic creation with retry on collision | |
| - **Temp XML naming:** `TestResult_{user}_{machine}_{timestamp}.xml` — timestamp-based name only (no PID) | |
| - **File creation:** Uses `FileMode.CreateNew` for atomic creation with retry on collision; millisecond timestamps + `CreateNew` retries provide uniqueness |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
test/Microsoft.TestPlatform.Extensions.HtmlLogger.UnitTests/HtmlLoggerTests.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Youssef Victor <youssefvictor00@gmail.com>
Tighten the HTML logger collision fix by restoring the intended millisecond timestamp format, keeping atomic create-new file allocation testable through IFileHelper, dropping unrelated docs churn from the PR, and adding coverage for retry-on-collision behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| using var _ = _fileHelper.GetStream(fullFilePath, FileMode.CreateNew, FileAccess.Write, FileShare.None); | ||
| return fullFilePath; | ||
| } | ||
| catch (IOException) when (File.Exists(fullFilePath)) |
There was a problem hiding this comment.
GenerateUniqueFilePath retries on IOException but uses static File.Exists(fullFilePath) in the catch filter. Since this class already abstracts file operations via IFileHelper, consider using _fileHelper.Exists(fullFilePath) (or checking the specific IOException/HResult for file-exists) so the logic stays consistent and easier to unit test without touching the real filesystem.
| catch (IOException) when (File.Exists(fullFilePath)) | |
| catch (IOException) when (_fileHelper.Exists(fullFilePath)) |
| _htmlLogger.TestRunCompleteHandler(new object(), new TestRunCompleteEventArgs(null, false, true, null, null, null, TimeSpan.Zero)); | ||
|
|
||
| Assert.IsNotNull(_htmlLogger.XmlFilePath); | ||
| createdFilePath = _htmlLogger.XmlFilePath; |
There was a problem hiding this comment.
XmlFilePathShouldContainMillisecondTimestampForCrossProcessUniqueness calls TestRunCompleteHandler without setting up IFileHelper.GetStream for the new FileMode.CreateNew call, so the mock returns null Streams and the test doesn’t reflect real file creation. Consider setting up GetStream to return a disposable Stream (e.g., MemoryStream) and optionally verifying the CreateNew overload is invoked to keep the test robust.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
src/Microsoft.TestPlatform.Extensions.HtmlLogger/HtmlLogger.cs:366
GenerateUniqueFilePathusesFile.Exists(fullFilePath)in the exception filter, bypassing the injectedIFileHelperabstraction. This makes the behavior harder to test/mocks inconsistent (and couples the logger to the physical filesystem even when a customIFileHelperis provided). Prefer using_fileHelper.Exists(fullFilePath)in the filter, and update the unit test setup accordingly.
// Use FileMode.CreateNew for atomic "create if not exists" to avoid
// cross-process race conditions when multiple vstest processes run in parallel.
using var _ = _fileHelper.GetStream(fullFilePath, FileMode.CreateNew, FileAccess.Write, FileShare.None);
return fullFilePath;
}
catch (IOException) when (File.Exists(fullFilePath))
{
Summary
Fixes #15404
When multiple vstest.console processes run in parallel with the HTML logger, temporary XML result files can collide because:
Changes
\src/Microsoft.TestPlatform.Extensions.HtmlLogger/HtmlLogger.cs\
\ est/Microsoft.TestPlatform.Extensions.HtmlLogger.UnitTests/HtmlLoggerTests.cs\
Documentation
Testing
All 34 HTML logger unit tests pass on both net9.0 and net48.