Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Helix/GenerateHelixWorkItems.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ Param(

[bool]$IsValidateWindowsAppSDKRun = $false,

# When true, engages the lifted system-composition switcher for this pass by passing
# /p:SwitcherMode=true to te.exe. This both flips the backend in ModuleSetup and makes the
# test infra prefer .master.switcher.<ext> baselines (falling back to .master.<ext>).
[bool]$SwitcherMode = $false,

[string]$TaefExePath
)

Expand Down Expand Up @@ -76,6 +81,10 @@ if ($HostingMode) {
$taefExtraParameters = "/p:HostingMode=$HostingMode"
}

if ($SwitcherMode) {
$taefExtraParameters = "$taefExtraParameters /p:SwitcherMode=true".Trim()
}

$TestBinaryDirectoryPath = $TestBinaryPath

& $PSScriptRoot\common\pipeline\GenerateHelixWorkItems.ps1 -TestFilePattern $TestFilePattern `
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ parameters:
testSuite: 'DevTestSuite'
taefQuery: ''
hostingMode: ''
switcherMode: 'false'
targetOsVersion: ''
taefExePath: ''

Expand All @@ -19,4 +20,4 @@ steps:
inputs:
targetType: filePath
filePath: Helix\GenerateHelixWorkItems.ps1
arguments: -TaefExePath "${{ parameters.taefExePath }}" -TestFilePattern "${{ parameters.testFilePathPattern }}" -TestBinaryPath "${{ parameters.testBinaryPath }}" -OutputProjFile "${{ parameters.outputProjDir }}\${{ parameters.outputProjFileName }}" -JobTestSuiteName "${{ parameters.testSuite }}" -CustomTaefQuery "${{ parameters.taefQuery }}" -HostingMode "${{ parameters.hostingMode }}" -TargetOSVersion ${{ parameters.targetOsVersion}} -TestExecutionMultiplier $(_testExecutionMultiplier) -RunIgnoredTests $(_runIgnoredTests) -IsValidateWindowsAppSDKRun $(isValidateWindowsAppSDKRun)
arguments: -TaefExePath "${{ parameters.taefExePath }}" -TestFilePattern "${{ parameters.testFilePathPattern }}" -TestBinaryPath "${{ parameters.testBinaryPath }}" -OutputProjFile "${{ parameters.outputProjDir }}\${{ parameters.outputProjFileName }}" -JobTestSuiteName "${{ parameters.testSuite }}" -CustomTaefQuery "${{ parameters.taefQuery }}" -HostingMode "${{ parameters.hostingMode }}" -SwitcherMode ${{ parameters.switcherMode }} -TargetOSVersion ${{ parameters.targetOsVersion}} -TestExecutionMultiplier $(_testExecutionMultiplier) -RunIgnoredTests $(_runIgnoredTests) -IsValidateWindowsAppSDKRun $(isValidateWindowsAppSDKRun)
128 changes: 128 additions & 0 deletions build/AzurePipelinesTemplates/WinUI-RunSwitcherTests-Stage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
#
# Runs the composition switcher tests on a ge_current lab VM under /p:SwitcherMode=true.
# Self-contained (modeled on WinUI-PGO-Train-Stage.yml, which uses the same ge_current pool) so
# it does not touch the shared per-OS RunTests matrix.
#
# First run targets the two engagement certifiers ("*SwitcherTests*") to prove the switcher
# engages end-to-end in the pipeline. To run the full master-backed suite, change testSelector
# to: "*" -TestsWithMasterFilesOnly (keep /p:SwitcherMode=true so switcher masters are selected).
parameters:
- name: testSelector
type: string
default: '*SwitcherTests*'

stages:
- stage: RunSwitcherTests
displayName: Run Switcher Tests (ge_current)
dependsOn: Build
condition: succeeded()
jobs:
- job: RunSwitcherTests_x86chk
pool:
type: windows
isCustom: true
name: WinDevPool-Test
demands: ImageOverride -equals ge_current-vhdx_enterprise
timeoutInMinutes: 180
variables:
# WinUI-InternalFeed (group 6276) carries the CompositionSwitcherLafToken variable that unlocks the
# CompositionEngine LAF for the switcher. It is referenced by name only; the value lives in ADO
# Library and never appears in this (public) yaml. This group is already loaded/authorized for the
# WinUI-GitHub-PR pipeline (def 195405).
- group: WinUI-InternalFeed
- name: buildPlatform
value: 'x86'
- name: normalizedConfiguration
value: 'chk'
- name: buildFolderName
value: x86chk
- name: incomingArtifactsPath
value: $(Build.ArtifactStagingDirectory)\incoming
- name: testPayloadDir
value: $(Build.SourcesDirectory)\TestPayload
- name: testPayloadDirInner
value: $(testPayloadDir)\x86chk
- name: ob_outputDirectory
value: c:\uploadroot
- name: ob_artifactBaseName
value: 'switcher_x86chk'
- name: ob_sdl_binskim_enabled
value: false

steps:
- script: |
reg query "HKLM\Software\Microsoft\Windows NT\CurrentVersion"
displayName: Display OS version info

- task: NuGetAuthenticate@1

- task: NuGetCommand@2
displayName: 'NuGet restore Lifted XAML dependencies'
inputs:
command: 'custom'
arguments: 'restore packages.config -ConfigFile nuget.config -PackagesDirectory $(Build.SourcesDirectory)\packages'
includeNuGetOrg: false

- template: WinUI-DownloadPipelineArtifacts-Steps.yml
parameters:
enableUseOutputFromPreviousBuild: true
artifactName: drop_x86chk
targetPath: $(incomingArtifactsPath)

- task: powershell@2
displayName: Prepare test payload
inputs:
targetType: filePath
filePath: test\CreateTestPayload.ps1
arguments: -BinSourceRoot $(incomingArtifactsPath) -Platform x86 -Configuration chk -Mode DevTestSuite -ShowPayload -SkipSymbols

# The switcher is engaged via the public CompositionEngine Limited Access Feature API
# (CompositionEngine::TrySetProcessEngine(System), called from the test's ModuleSetup under
# /p:SwitcherMode=true). On a ge_current image the feature is enabled by default and the LAF
# is available, so no additional machine configuration is needed here. If the image is not
# provisioned with the feature, the test reports "did not engage" and skips - which is the
# signal that the test pool needs the switcher feature enabled.

- task: powershell@2
displayName: Run Switcher Tests (WPF)
timeoutInMinutes: 120
inputs:
targetType: inline
workingDirectory: $(testPayloadDirInner)
script: |
.\runtests.cmd "${{ parameters.testSelector }}" -HostingMode:WPF /p:SwitcherMode=true /p:SwitcherLafToken=$(CompositionSwitcherLafToken)
exit $LASTEXITCODE

- task: PublishTestResults@2
condition: always()
inputs:
testResultsFormat: xUnit
testResultsFiles: 'te.wtl;testResults-*.xml'
searchFolder: $(testPayloadDirInner)
mergeTestResults: true
failTaskOnFailedTests: true
testRunTitle: 'SwitcherTests x86chk'

# Publish the generated .save.xml trees + diffs/screenshots so switcher baselines can be
# captured from this run (they are intentionally NOT committed; see PR description).
- task: CopyFiles@2
condition: always()
displayName: Collect generated trees for baselining
inputs:
sourceFolder: '$(USERPROFILE)\Pictures\XamlTAEFOutput'
contents: |
**\*.save.xml
**\*.out.xml
**\*.png
**\*.jpg
targetFolder: $(ob_outputDirectory)\SwitcherBaselining
ignoreMakeDirErrors: true

- task: PublishPipelineArtifact@1
condition: always()
displayName: Publish switcher output for baselining
inputs:
targetPath: $(ob_outputDirectory)
artifact: 'switcher_x86chk'
7 changes: 7 additions & 0 deletions build/WinUI-GitHub-PR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,13 @@ extends:
# Test results are published but do not gate the pipeline yet.
failOnTestFailure: false

# Composition switcher tests on a ge_current agent under /p:SwitcherMode=true. The stage template lives
# in THIS repo (self, not @WinUIInternal) because it is part of the switcher work. It unlocks the
# CompositionEngine LAF via the CompositionSwitcherLafToken variable (ADO Library group WinUI-InternalFeed,
# referenced by name only — the value never appears in this public yaml).
- ${{ if eq(parameters.runFullValidation, true) }}:
- template: AzurePipelinesTemplates\WinUI-RunSwitcherTests-Stage.yml

- ${{ if eq(parameters.runFullValidation, true) }}:
- template: build\AzurePipelinesTemplates\WinUI-RunStaticTests-Stage.yml@WinUIInternal
parameters:
Expand Down
38 changes: 37 additions & 1 deletion dxaml/test/infra/client/lib/Utilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1469,6 +1469,17 @@ namespace Private { namespace Infrastructure {

}

// Returns true when the test run was launched with /p:SwitcherMode=true, i.e. the lifted
// system-composition switcher is engaged process-wide (see ModuleSetup in ModuleCleanup.cpp).
// Under switcher the composition tree can differ from the baseline WUC path, so a
// switcher-specific baseline (.master.switcher.<ext>) is preferred when present.
static bool IsSwitcherMode()
{
WEX::Common::String switcherModeParam;
return SUCCEEDED(WEX::TestExecution::RuntimeParameters::TryGetValue(L"SwitcherMode", switcherModeParam))
&& (switcherModeParam.CompareNoCase(L"true") == 0 || switcherModeParam == L"1");
}

bool Utilities::DoVerification(
_In_ PCWSTR fileExtension,
_In_opt_ HSTRING variation,
Expand Down Expand Up @@ -1501,7 +1512,32 @@ namespace Private { namespace Infrastructure {
wrl::ComPtr<wst::IStorageFile> spMasterFile;

spOutputFile = GetStorageFile(strOutputFilenameWithPath.Get());
spMasterFile = GetStorageFile(strMasterFilenameWithPath.Get());

// Under switcher mode, prefer a switcher-specific baseline (.master.switcher.<ext>) if one
// exists. This lets the switcher path own a different visual tree without overwriting the
// baseline WUC masters, so non-switcher runs keep comparing against .master.<ext> unchanged.
if (IsSwitcherMode())
{
wrl::Wrappers::HString switcherSuffix;
LogThrow_IfFailed(switcherSuffix.Set((std::wstring(L".master.switcher.") + fileExtension).c_str()));
auto switcherHelper = GenerateFileNameHelper(variation, switcherSuffix.Get());
wrl::Wrappers::HString switcherFilenameWithPath = GetFileName(PrependPath(GetMastersFolderPath(), switcherHelper));
wrl::ComPtr<wst::IStorageFile> spSwitcherMaster = GetStorageFile(switcherFilenameWithPath.Get());
if (spSwitcherMaster)
{
spMasterFile = spSwitcherMaster;
LogThrow_IfFailed(masterFileNameSuffix.Set((std::wstring(L".master.switcher.") + fileExtension).c_str()));
masterFileNameHelper = switcherHelper;
const wrl::Wrappers::HString switcherFilename = GetFileName(switcherHelper);
LogThrow_IfFailed(strMasterFilename.Set(switcherFilename.GetRawBuffer(nullptr)));
LogThrow_IfFailed(strMasterFilenameWithPath.Set(switcherFilenameWithPath.GetRawBuffer(nullptr)));
}
}

if (!spMasterFile)
{
spMasterFile = GetStorageFile(strMasterFilenameWithPath.Get());
}

// If neither file exists, then this file was apparently not needed (such as due to this
// index being for a surface which is no longer referenced). Everything is good in this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@
<ClInclude Include="graphics\rendering\ShutdownTests.h" />
<ClInclude Include="graphics\rendering\SISTests.h" />
<ClInclude Include="graphics\rendering\SuspendResumeTests.h" />
<ClInclude Include="graphics\rendering\SwitcherTests.h" />
<ClInclude Include="graphics\rendering\TextBlockClippingTests.h" />
<ClInclude Include="graphics\rendering\TextBlockTests.h" />
<ClInclude Include="graphics\rendering\TextBoxTests.h" />
Expand Down Expand Up @@ -265,6 +266,7 @@
<ClCompile Include="graphics\rendering\ShapeTests.cpp" />
<ClCompile Include="graphics\rendering\Matrix3DProjectionTests.cpp" />
<ClCompile Include="graphics\rendering\SuspendResumeTests.cpp" />
<ClCompile Include="graphics\rendering\SwitcherTests.cpp" />
<ClCompile Include="graphics\rendering\CompositionTargetTests.cpp" />
<ClCompile Include="graphics\rendering\DebugCounterTests.cpp" />
<ClCompile Include="graphics\rendering\ShutdownTests.cpp" />
Expand Down
Loading
Loading