Skip to content

Conversation

@titusfortner
Copy link
Member

@titusfortner titusfortner commented Jan 5, 2026

User description

Breaking this out from #16818

💥 What does this PR do?

  • Do not run bazel tests in parallel
  • Bazel runfiles doesn't do directories, just files; for Mac/Linux the directory symlinks work as files, in Windows it does not work, need to get a file and then walk up to the parent directory
  • Guard one test and add synchronization to another

🔧 Implementation Notes

  • We could use a relative path without Runfiles, but this seemed easier fix.

🔄 Types of changes

  • Bug fix (backwards compatible)

PR Type

Bug fix, Tests


Description

  • Fix .NET tests on Windows with Bazel by handling runfiles directories

  • Prevent NUnit test parallelism to avoid driver instance conflicts

  • Add synchronization to WebElementTest.ShouldSubmitElement test

  • Guard Firefox signed directory addon test on Windows platform


Diagram Walkthrough

flowchart LR
  A["Bazel Runfiles<br/>Directory Handling"] -->|"Fallback to<br/>manifest.json"| B["Get Parent<br/>Directory Path"]
  C["NUnit Test<br/>Parallelism"] -->|"Add --workers=1"| D["Sequential<br/>Test Execution"]
  E["WebElement<br/>Submit Test"] -->|"Add WaitFor<br/>Synchronization"| F["Reliable URL<br/>Verification"]
  G["Firefox Addon<br/>Test"] -->|"Platform Guard"| H["Skip on<br/>Windows"]
Loading

File Walkthrough

Relevant files
Bug fix
WebExtensionTest.cs
Handle Bazel runfiles directory resolution on Windows       

dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs

  • Modified LocateRelativePath to handle Bazel runfiles directory
    resolution on Windows
  • Added fallback logic to locate manifest.json file and extract parent
    directory when direct path resolution fails
  • Maintains backward compatibility with FileNotFoundException catch
    block
+10/-1   
WebElementTest.cs
Add synchronization to element submit test                             

dotnet/test/common/WebElementTest.cs

  • Added synchronization to ShouldSubmitElement test using WaitFor helper
  • Wrapped URL assertion in lambda with explicit wait condition
  • Prevents race condition where URL redirect hasn't completed yet
+6/-1     
FirefoxDriverTest.cs
Guard Firefox addon test and fix path resolution                 

dotnet/test/firefox/FirefoxDriverTest.cs

  • Added IgnorePlatform attribute to
    ShouldInstallAndUninstallSignedDirAddon test
  • Skips test on Windows due to ERROR_CORRUPT_FILE issue with signed
    directory addons
  • Refactored GetPath method to use Bazel Runfiles for directory
    resolution
  • Added fallback to legacy path resolution for non-Bazel environments
+13/-3   
Configuration changes
dotnet_nunit_test_suite.bzl
Disable NUnit test parallelism for Bazel                                 

dotnet/private/dotnet_nunit_test_suite.bzl

  • Introduced _NUNIT_ARGS constant with --workers=1 flag
  • Prevents NUnit test parallelism since Bazel tests share single driver
    instance
  • Applied _NUNIT_ARGS to all browser test configurations
+5/-1     
Dependencies
BUILD.bazel
Add Runfiles NuGet dependency                                                       

dotnet/test/firefox/BUILD.bazel

  • Added Runfiles NuGet package dependency to Firefox test suite
  • Enables Bazel runfiles API usage for path resolution in tests
+1/-0     

@selenium-ci selenium-ci added C-dotnet .NET Bindings B-build Includes scripting, bazel and CI integrations labels Jan 5, 2026
@qodo-code-review
Copy link
Contributor

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Null path fallback: GetPath may return null because Path.GetDirectoryName(path) is not null-guarded if
Rlocation returns null/empty, leading to potential downstream failures instead of graceful
degradation.

Referred Code
    string path = Bazel.Runfiles.Create().Rlocation($"_main/common/extensions/{name}/manifest.json");
    return Path.GetDirectoryName(path);
}

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Disabling parallelism globally slows tests

The suggestion highlights that adding --workers=1 to disable NUnit parallelism,
while fixing a bug, will slow down the test suite. It recommends this be a
temporary measure, with a future goal of re-enabling parallel execution.

Examples:

dotnet/private/dotnet_nunit_test_suite.bzl [110-112]
_NUNIT_ARGS = [
    "--workers=1",  # Bazel tests share a single driver instance; prevent NUnit parallelism
]
dotnet/private/dotnet_nunit_test_suite.bzl [169]
                    args = _NUNIT_ARGS + _BROWSERS[browser]["args"] + _HEADLESS_ARGS,

Solution Walkthrough:

Before:

# dotnet/private/dotnet_nunit_test_suite.bzl

csharp_test(
    name = browser_test_name,
    ...
    args = _BROWSERS[browser]["args"] + _HEADLESS_ARGS,
    ...
)

After:

# dotnet/private/dotnet_nunit_test_suite.bzl

_NUNIT_ARGS = [
    "--workers=1",  # Prevent NUnit parallelism
]

csharp_test(
    name = browser_test_name,
    ...
    args = _NUNIT_ARGS + _BROWSERS[browser]["args"] + _HEADLESS_ARGS,
    ...
)
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a significant performance regression by disabling parallelism with --workers=1, and rightly frames it as a strategic trade-off that should be revisited.

Medium
Possible issue
Prevent returning null or empty paths

Improve path resolution by checking if the resolved path from Rlocation is null
or empty and falling back to the legacy logic. This prevents returning null or
empty paths.

dotnet/test/firefox/FirefoxDriverTest.cs [376-387]

 try
 {
     // For directories, locate a file inside and get parent (runfiles manifest only lists files)
-    string path = Bazel.Runfiles.Create().Rlocation($"_main/common/extensions/{name}/manifest.json");
-    return Path.GetDirectoryName(path);
+    string manifestPath = Bazel.Runfiles.Create().Rlocation($"_main/common/extensions/{name}/manifest.json");
+    if (string.IsNullOrEmpty(manifestPath))
+    {
+        // Fallback for non-Bazel environments or if runfiles resolution fails.
+        string sCurrentDirectory = AppDomain.CurrentDomain.BaseDirectory;
+        string sFile = Path.Combine(sCurrentDirectory, "../../../../common/extensions/" + name);
+        return Path.GetFullPath(sFile);
+    }
+    return Path.GetDirectoryName(manifestPath);
 }
 catch (FileNotFoundException)
 {
     string sCurrentDirectory = AppDomain.CurrentDomain.BaseDirectory;
     string sFile = Path.Combine(sCurrentDirectory, "../../../../common/extensions/" + name);
     return Path.GetFullPath(sFile);
 }
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies two potential edge cases (empty string from Rlocation and null from Path.GetDirectoryName) and provides a robust fix that improves the reliability of path resolution.

Medium
Assert the wait result explicitly

Replace Assert.That(..., Throws.Nothing) with Assert.IsTrue(...) to correctly
validate the boolean result of the WaitFor condition, ensuring the test fails if
the navigation does not complete successfully.

dotnet/test/common/WebElementTest.cs [145-150]

-Assert.That(
-    () =>
-        WaitFor(
-            () => driver.Url.StartsWith(resultPage),
-            "We are not redirected to the resultPage after submitting web element"),
-    Throws.Nothing);
+Assert.IsTrue(
+    WaitFor(
+        () => driver.Url.StartsWith(resultPage),
+        "We are not redirected to the resultPage after submitting web element"),
+    "Submit did not navigate to the result page within the timeout");
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly points out that Assert.That(..., Throws.Nothing) does not check the return value of the WaitFor method. Using Assert.IsTrue makes the test assertion more explicit and correct.

Medium
Handle empty path resolution results

Add a check to handle cases where runfiles.Rlocation returns a null or empty
string for manifestPath, falling back to Path.GetFullPath(path) to prevent
returning an invalid path.

dotnet/test/common/BiDi/WebExtension/WebExtensionTest.cs [98-100]

 // For directories, locate a file inside and get parent (runfiles manifest only lists files)
 string manifestPath = runfiles.Rlocation($"_main/{path}/manifest.json");
+if (string.IsNullOrEmpty(manifestPath))
+{
+    return Path.GetFullPath(path);
+}
 return Path.GetDirectoryName(manifestPath) ?? Path.GetFullPath(path);
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies a potential bug where an empty string from Rlocation would lead to an invalid path being returned, and the proposed fix handles this edge case gracefully.

Low
  • More

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-build Includes scripting, bazel and CI integrations C-dotnet .NET Bindings Review effort 2/5

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants