diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 31afc209..8516e126 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -75,6 +75,43 @@ jobs: path: TestResults/ retention-days: 5 + test-hardware-windows: + name: 🧪 Tests (Windows, Hardware) + needs: build + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: ⚙️ Install prerequisites + run: ./init.ps1 -UpgradePrerequisites -NoNuGetCredProvider + shell: pwsh + - name: 📦 Download build + uses: actions/download-artifact@v4 + with: + name: build-windows + path: bin/ + # GitHub-hosted windows-latest runners can execute these COM/Direct2D/WMI/Shell runtime + # tests (Direct2D uses the WARP software rasterizer, so no GPU is required). They remain + # tagged RequiresHardware so the locked-down Azure DevOps 1ES build pool keeps excluding + # them, but we exercise the real runtime code paths here rather than only on dev machines. + - name: 🧪 Run hardware-dependent tests + run: | + dotnet test --no-build -c ${{ env.BuildConfiguration }} ` + --filter "TestCategory=RequiresHardware" ` + --blame-hang-timeout 600s ` + --blame-crash ` + --logger trx ` + --results-directory TestResults + shell: pwsh + - name: 📢 Upload test results + uses: actions/upload-artifact@v4 + if: always() + with: + name: test-results-hardware-windows + path: TestResults/ + retention-days: 5 + test-fast-linux: name: 🧪 Tests (Linux) runs-on: ubuntu-latest @@ -242,18 +279,20 @@ jobs: validate: name: ✅ Validate if: always() - needs: [build, test-fast-windows, test-fast-linux, test-heavy, integration-test] + needs: [build, test-fast-windows, test-hardware-windows, test-fast-linux, test-heavy, integration-test] runs-on: ubuntu-latest steps: - name: Check results run: | echo "Build: ${{ needs.build.result }}" echo "Windows tests: ${{ needs.test-fast-windows.result }}" + echo "Windows hardware tests: ${{ needs.test-hardware-windows.result }}" echo "Linux tests: ${{ needs.test-fast-linux.result }}" echo "Heavy tests: ${{ needs.test-heavy.result }}" echo "Integration tests: ${{ needs.integration-test.result }}" if [[ "${{ needs.build.result }}" != "success" || "${{ needs.test-fast-windows.result }}" != "success" || + "${{ needs.test-hardware-windows.result }}" != "success" || "${{ needs.test-fast-linux.result }}" != "success" || "${{ needs.test-heavy.result }}" != "success" || "${{ needs.integration-test.result }}" != "success" ]]; then diff --git a/test/GenerationSandbox.BuildTask.Tests/COMTests.cs b/test/GenerationSandbox.BuildTask.Tests/COMTests.cs index 257ee393..d031a266 100644 --- a/test/GenerationSandbox.BuildTask.Tests/COMTests.cs +++ b/test/GenerationSandbox.BuildTask.Tests/COMTests.cs @@ -132,7 +132,7 @@ private static void CompileOnlyCreateCommittedResourceGenericOverload(ID3D12Devi [Fact] - [Trait("TestCategory", "RequiresHardware")] // D3D APIs fail in cloud VMs + [Trait("TestCategory", "RequiresHardware")] // Excluded from the locked-down ADO 1ES build pool; runs on GitHub Actions (Direct2D uses WARP). public void ReturnValueMarshalsCorrectly() { // Create an ID2D1HwndRenderTarget and verify GetHwnd returns the original HWND. @@ -188,7 +188,9 @@ static LRESULT WndProc(HWND hWnd, uint msg, WPARAM wParam, LPARAM lParam) // 3. Prepare render target properties. D2D1_RENDER_TARGET_PROPERTIES rtProps = new() { - type = D2D1_RENDER_TARGET_TYPE.D2D1_RENDER_TARGET_TYPE_DEFAULT, + // Use WARP (software) rendering so this exercises the same D2D render-target + // creation and HWND marshaling code paths on GPU-less CI VMs without a hardware GPU. + type = D2D1_RENDER_TARGET_TYPE.D2D1_RENDER_TARGET_TYPE_SOFTWARE, pixelFormat = new D2D1_PIXEL_FORMAT { format = DXGI_FORMAT.DXGI_FORMAT_UNKNOWN, @@ -224,7 +226,7 @@ static LRESULT WndProc(HWND hWnd, uint msg, WPARAM wParam, LPARAM lParam) } [Fact] - [Trait("TestCategory", "RequiresHardware")] // WMI APIs don't work in cloud VMs. + [Trait("TestCategory", "RequiresHardware")] // Excluded from the locked-down ADO 1ES build pool; runs on GitHub Actions. public void IWbemServices_GetObject_Works() { Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Test calls Windows-specific APIs"); diff --git a/test/GenerationSandbox.Tests/ComRuntimeTests.cs b/test/GenerationSandbox.Tests/ComRuntimeTests.cs index f2e25a4e..1277777a 100644 --- a/test/GenerationSandbox.Tests/ComRuntimeTests.cs +++ b/test/GenerationSandbox.Tests/ComRuntimeTests.cs @@ -35,7 +35,7 @@ public void RemotableInterface() } [Fact] - [Trait("TestCategory", "RequiresHardware")] // D3D APIs fail in cloud VMs + [Trait("TestCategory", "RequiresHardware")] // Excluded from the locked-down ADO 1ES build pool; runs on GitHub Actions (Direct2D uses WARP). public void ReturnValueMarshalsCorrectly() { // Create an ID2D1HwndRenderTarget and verify GetHwnd returns the original HWND. @@ -90,7 +90,9 @@ static LRESULT WndProc(HWND hWnd, uint msg, WPARAM wParam, LPARAM lParam) // 3. Prepare render target properties. D2D1_RENDER_TARGET_PROPERTIES rtProps = new() { - type = D2D1_RENDER_TARGET_TYPE.D2D1_RENDER_TARGET_TYPE_DEFAULT, + // Use WARP (software) rendering so this exercises the same D2D render-target + // creation and HWND marshaling code paths on GPU-less CI VMs without a hardware GPU. + type = D2D1_RENDER_TARGET_TYPE.D2D1_RENDER_TARGET_TYPE_SOFTWARE, pixelFormat = new D2D1_PIXEL_FORMAT { format = DXGI_FORMAT.DXGI_FORMAT_UNKNOWN, @@ -126,7 +128,7 @@ static LRESULT WndProc(HWND hWnd, uint msg, WPARAM wParam, LPARAM lParam) } [Fact] - [Trait("TestCategory", "RequiresHardware")] // WMI APIs don't work in cloud VMs. + [Trait("TestCategory", "RequiresHardware")] // Excluded from the locked-down ADO 1ES build pool; runs on GitHub Actions. public void IWbemServices_GetObject_Works() { Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Test calls Windows-specific APIs"); @@ -161,7 +163,7 @@ public void IWbemServices_GetObject_Works() } [Fact] - [Trait("TestCategory", "RequiresHardware")] // WMI APIs don't work in cloud VMs. + [Trait("TestCategory", "RequiresHardware")] // Needs Shell/Explorer COM; excluded from the locked-down ADO 1ES build pool, runs on GitHub Actions. public void CanCallIDispatchOnlyMethods() { Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Test calls Windows-specific APIs"); diff --git a/test/GenerationSandbox.Unmarshalled.Tests/COMTests.cs b/test/GenerationSandbox.Unmarshalled.Tests/COMTests.cs index fc6b0cd1..5e5776d6 100644 --- a/test/GenerationSandbox.Unmarshalled.Tests/COMTests.cs +++ b/test/GenerationSandbox.Unmarshalled.Tests/COMTests.cs @@ -43,7 +43,7 @@ public unsafe void CocreatableClassesWithImplicitInterfaces() #endif [Fact] - [Trait("TestCategory", "RequiresHardware")] // D3D APIs fail in cloud VMs + [Trait("TestCategory", "RequiresHardware")] // Excluded from the locked-down ADO 1ES build pool; runs on GitHub Actions (Direct2D uses WARP). public unsafe void ReturnValueMarshalsCorrectly() { // Create an ID2D1HwndRenderTarget and verify GetHwnd returns the original HWND. @@ -78,7 +78,9 @@ public unsafe void ReturnValueMarshalsCorrectly() // 3. Prepare render target properties. D2D1_RENDER_TARGET_PROPERTIES rtProps = new() { - type = D2D1_RENDER_TARGET_TYPE.D2D1_RENDER_TARGET_TYPE_DEFAULT, + // Use WARP (software) rendering so this exercises the same D2D render-target + // creation and HWND marshaling code paths on GPU-less CI VMs without a hardware GPU. + type = D2D1_RENDER_TARGET_TYPE.D2D1_RENDER_TARGET_TYPE_SOFTWARE, pixelFormat = new D2D1_PIXEL_FORMAT { format = DXGI_FORMAT.DXGI_FORMAT_UNKNOWN,