test(vulkan): isolate the hardware witness lane
Tag the production offscreen witness as Lane=Vulkan, exclude capability-owned tests from the portable Release filter, and give lavapipe an explicit trait-only invocation after the portable Vulkan contracts. Document the lane and pin witness, portable-filter, and workflow ownership without initializing Vulkan. Mutations performed and restored: 1. Removed the witness trait: VulkanLaneOwnershipContractTests first failed Assert.Matches because the Lane=Vulkan/Fact/method pattern was absent. 2. Removed Lane!=Vulkan from the default filter: the contract first failed Assert.Contains, not found Lane!=Vulkan. 3. Weakened the dedicated invocation to Lane!=Vulkan: the contract first failed Assert.Contains, not found --filter Lane=Vulkan in the hardware step. 4. Narrowed the dedicated invocation with FullyQualifiedName: the contract first failed Assert.DoesNotContain because FullyQualifiedName was present at position 231.
This commit is contained in:
parent
15a796c3a1
commit
7506e5f14e
5 changed files with 112 additions and 5 deletions
11
.github/workflows/headless-portability.yml
vendored
11
.github/workflows/headless-portability.yml
vendored
|
|
@ -311,7 +311,16 @@ jobs:
|
||||||
dotnet test `
|
dotnet test `
|
||||||
tests/AcDream.App.Tests/AcDream.App.Tests.csproj `
|
tests/AcDream.App.Tests/AcDream.App.Tests.csproj `
|
||||||
-c Release `
|
-c Release `
|
||||||
--filter "FullyQualifiedName~AcDream.App.Tests.Rendering.Gpu.Vk"
|
--filter "FullyQualifiedName~AcDream.App.Tests.Rendering.Gpu.Vk&Lane!=Vulkan"
|
||||||
|
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||||
|
|
||||||
|
- name: Test the Vulkan hardware lane on lavapipe
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
dotnet test `
|
||||||
|
tests/AcDream.App.Tests/AcDream.App.Tests.csproj `
|
||||||
|
-c Release `
|
||||||
|
--filter "Lane=Vulkan"
|
||||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||||
|
|
||||||
# (a) + (b): one run, two gates. The harness opens a real window, runs the
|
# (a) + (b): one run, two gates. The harness opens a real window, runs the
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,10 @@ The command verifies that `AcDream.slnx` contains every `.csproj` under `src/`,
|
||||||
then discovers and runs every hermetic test in every default test assembly once
|
then discovers and runs every hermetic test in every default test assembly once
|
||||||
in a fresh Release process. It does not retry failures. Tests carrying an
|
in a fresh Release process. It does not retry failures. Tests carrying an
|
||||||
explicit non-hermetic `Lane` trait (`InstalledDat`, `PreparedPackage`, `Live`,
|
explicit non-hermetic `Lane` trait (`InstalledDat`, `PreparedPackage`, `Live`,
|
||||||
`Manual`, `Timing`, `Windows`, `Linux`, or `SystemFont`), `Purpose=Diagnostic`, or
|
`Manual`, `Timing`, `Windows`, `Linux`, `Vulkan`, or `SystemFont`),
|
||||||
`Status=KnownFailure` are excluded from the hermetic total and run through
|
`Purpose=Diagnostic`, or `Status=KnownFailure` are excluded from the hermetic
|
||||||
their owned lane instead. The graph currently contains 54 projects,
|
total and run through their owned lane instead. The graph currently contains
|
||||||
|
54 projects,
|
||||||
including all 17 maintained .NET tools and three render-pack SDK samples;
|
including all 17 maintained .NET tools and three render-pack SDK samples;
|
||||||
data-dependent tools and SDK samples are built but are not executed as tests.
|
data-dependent tools and SDK samples are built but are not executed as tests.
|
||||||
|
|
||||||
|
|
@ -108,6 +109,18 @@ and Forgejo fails a task that stops reporting as a zombie.
|
||||||
|
|
||||||
## Non-hermetic test lanes
|
## Non-hermetic test lanes
|
||||||
|
|
||||||
|
`Lane=Vulkan` owns tests that require a Vulkan loader, a Vulkan 1.3-capable
|
||||||
|
physical device with a graphics queue, and coherent host-visible readback
|
||||||
|
memory. The portable Release gate excludes this capability lane. The
|
||||||
|
`linux-vulkan` CI job installs lavapipe and runs it explicitly; missing Vulkan
|
||||||
|
capability is a failure there, not a skip. Run the same dedicated lane locally
|
||||||
|
on a capable device with:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
dotnet test tests/AcDream.App.Tests/AcDream.App.Tests.csproj -c Release `
|
||||||
|
--filter 'Lane=Vulkan'
|
||||||
|
```
|
||||||
|
|
||||||
Installed-DAT tests require an explicit opt-in and a retail DAT directory:
|
Installed-DAT tests require an explicit opt-in and a retail DAT directory:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ public sealed unsafe class MeshModernSharedIndexOffscreenTests
|
||||||
private const uint Prefix = 2;
|
private const uint Prefix = 2;
|
||||||
private static readonly object VulkanLock = new();
|
private static readonly object VulkanLock = new();
|
||||||
|
|
||||||
|
[Trait("Lane", "Vulkan")]
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CommittedProductionOrdinaryShader_RendersLocalSidecarsAtNonzeroTransformPrefix()
|
public void CommittedProductionOrdinaryShader_RendersLocalSidecarsAtNonzeroTransformPrefix()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace AcDream.App.Tests.Rendering.Gpu.Vk;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Keeps the capability-owned pixel witness out of the portable gate while
|
||||||
|
/// requiring the lavapipe job to execute the complete trait-owned lane.
|
||||||
|
/// This contract reads repository text only and never initializes Vulkan.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class VulkanLaneOwnershipContractTests
|
||||||
|
{
|
||||||
|
private const string WitnessMethod =
|
||||||
|
"CommittedProductionOrdinaryShader_RendersLocalSidecarsAtNonzeroTransformPrefix";
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void HardwareWitness_PortableFilterAndLavapipeOwnerStayAligned()
|
||||||
|
{
|
||||||
|
string root = RepositoryRoot();
|
||||||
|
string witness = File.ReadAllText(Path.Combine(
|
||||||
|
root,
|
||||||
|
"tests", "AcDream.App.Tests", "Rendering", "Gpu", "Vk",
|
||||||
|
"MeshModernSharedIndexOffscreenTests.cs"));
|
||||||
|
Assert.Matches(
|
||||||
|
new Regex(
|
||||||
|
"\\[Trait\\(\"Lane\", \"Vulkan\"\\)\\]\\s*"
|
||||||
|
+ "\\[Fact\\]\\s*public void " + WitnessMethod + "\\(",
|
||||||
|
RegexOptions.CultureInvariant),
|
||||||
|
witness);
|
||||||
|
Assert.Equal(1, Count(witness, "[Trait(\"Lane\", \"Vulkan\")]"));
|
||||||
|
|
||||||
|
string releaseGate = File.ReadAllText(Path.Combine(root, "tools", "run-release-gate.ps1"));
|
||||||
|
Match defaultFilter = Regex.Match(
|
||||||
|
releaseGate,
|
||||||
|
"\\[string\\]\\$TestFilter\\s*=\\s*'(?<filter>[^']+)'",
|
||||||
|
RegexOptions.CultureInvariant);
|
||||||
|
Assert.True(defaultFilter.Success, "Could not locate the portable Release gate's default filter.");
|
||||||
|
Assert.Contains("Lane!=Vulkan", defaultFilter.Groups["filter"].Value, StringComparison.Ordinal);
|
||||||
|
Assert.Equal(1, Count(defaultFilter.Groups["filter"].Value, "Lane!=Vulkan"));
|
||||||
|
|
||||||
|
string workflow = File.ReadAllText(Path.Combine(
|
||||||
|
root, ".github", "workflows", "headless-portability.yml"));
|
||||||
|
int install = workflow.IndexOf("- name: Install lavapipe, the Vulkan loader and Xvfb", StringComparison.Ordinal);
|
||||||
|
int portable = workflow.IndexOf("- name: Test the Vulkan backend's platform-independent decisions", StringComparison.Ordinal);
|
||||||
|
int hardware = workflow.IndexOf("- name: Test the Vulkan hardware lane on lavapipe", StringComparison.Ordinal);
|
||||||
|
Assert.True(install >= 0 && install < portable && portable < hardware);
|
||||||
|
|
||||||
|
string portableStep = Step(workflow, portable);
|
||||||
|
Assert.Contains(
|
||||||
|
"--filter \"FullyQualifiedName~AcDream.App.Tests.Rendering.Gpu.Vk&Lane!=Vulkan\"",
|
||||||
|
portableStep,
|
||||||
|
StringComparison.Ordinal);
|
||||||
|
|
||||||
|
string hardwareStep = Step(workflow, hardware);
|
||||||
|
Assert.DoesNotContain("FullyQualifiedName", hardwareStep, StringComparison.Ordinal);
|
||||||
|
Assert.DoesNotContain(WitnessMethod, hardwareStep, StringComparison.Ordinal);
|
||||||
|
Assert.Contains("--filter \"Lane=Vulkan\"", hardwareStep, StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string Step(string workflow, int start)
|
||||||
|
{
|
||||||
|
int next = workflow.IndexOf(" - name:", start + 1, StringComparison.Ordinal);
|
||||||
|
return next < 0 ? workflow[start..] : workflow[start..next];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int Count(string value, string needle)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
for (int index = 0; (index = value.IndexOf(needle, index, StringComparison.Ordinal)) >= 0;)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
index += needle.Length;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string RepositoryRoot()
|
||||||
|
{
|
||||||
|
var directory = new DirectoryInfo(AppContext.BaseDirectory);
|
||||||
|
while (directory is not null && !File.Exists(Path.Combine(directory.FullName, "AcDream.slnx")))
|
||||||
|
directory = directory.Parent;
|
||||||
|
return directory?.FullName
|
||||||
|
?? throw new InvalidOperationException("Could not locate the repository root.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -24,7 +24,7 @@ param(
|
||||||
[int]$BuildTimeoutSeconds = 900,
|
[int]$BuildTimeoutSeconds = 900,
|
||||||
[int]$TestTimeoutSeconds = 600,
|
[int]$TestTimeoutSeconds = 600,
|
||||||
[int]$HangTimeoutSeconds = 180,
|
[int]$HangTimeoutSeconds = 180,
|
||||||
[string]$TestFilter = 'Lane!=InstalledDat&Lane!=PreparedPackage&Lane!=Live&Lane!=Manual&Lane!=Timing&Lane!=Windows&Lane!=Linux&Lane!=SystemFont&Purpose!=Diagnostic&Status!=KnownFailure',
|
[string]$TestFilter = 'Lane!=InstalledDat&Lane!=PreparedPackage&Lane!=Live&Lane!=Manual&Lane!=Timing&Lane!=Windows&Lane!=Linux&Lane!=Vulkan&Lane!=SystemFont&Purpose!=Diagnostic&Status!=KnownFailure',
|
||||||
[switch]$SkipRestore,
|
[switch]$SkipRestore,
|
||||||
[switch]$SkipBuild
|
[switch]$SkipBuild
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue