commit 8b475657fb80e1685eb2e1a1ac7e9a29e22bef7a
parent d94b94bfaff4b2262780a7c80a837fefe8d55870
Author: JohnMcPMS <johnmcp@microsoft.com>
Date: Wed, 18 Mar 2020 15:12:34 -0700
Run tests in packaged context (#59)
Diffstat:
6 files changed, 212 insertions(+), 7 deletions(-)
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
@@ -19,12 +19,15 @@ variables:
steps:
- task: NuGetToolInstaller@1
+ displayName: Install Nuget
- task: NuGetCommand@2
+ displayName: Restore Packages
inputs:
restoreSolution: '$(solution)'
- task: VSBuild@1
+ displayName: Build Solution
inputs:
platform: 'x86'
solution: '$(solution)'
@@ -32,26 +35,61 @@ steps:
msbuildArgs: '/p:AppxBundlePlatforms="$(buildPlatform)" /p:AppxPackageDir="$(appxPackageDir)" /p:AppxBundle=Always /p:UapAppxPackageBuildMode=StoreUpload'
- task: CmdLine@2
+ displayName: Run Tests Unpackaged
inputs:
script: |
- AppInstallerCLITests.exe -logto AICLI.log -s -r junit -o TEST-AppInstallerCLI-$(_artifact).xml
+ AppInstallerCLITests.exe -logto AICLI-Unpackaged.log -s -r junit -o TEST-AppInstallerCLI-Unpackaged.xml
workingDirectory: 'src\x64\Release\AppInstallerCLITests\'
- task: PublishBuildArtifacts@1
+ displayName: Publish Unpackaged Log
inputs:
- PathtoPublish: 'src\x64\Release\AppInstallerCLITests\AICLI.log'
- ArtifactName: 'TestPassLog'
+ PathtoPublish: 'src\x64\Release\AppInstallerCLITests\AICLI-Unpackaged.log'
+ ArtifactName: 'TestPassUnpackagedLog'
publishLocation: 'Container'
condition: succeededOrFailed()
- task: PublishBuildArtifacts@1
+ displayName: Publish Unpackaged Output
inputs:
- PathtoPublish: 'src\x64\Release\AppInstallerCLITests\TEST-AppInstallerCLI-$(_artifact).xml'
- ArtifactName: 'TestPassOutput'
+ PathtoPublish: 'src\x64\Release\AppInstallerCLITests\TEST-AppInstallerCLI-Unpackaged.xml'
+ ArtifactName: 'TestPassUnpackagedOutput'
+ publishLocation: 'Container'
+ condition: succeededOrFailed()
+
+- task: PowerShell@2
+ displayName: Install Dependencies
+ inputs:
+ targetType: 'inline'
+ script: |
+ Add-AppxPackage AppInstallerCLIPackage_0.0.0.2_Test\Dependencies\x64\Microsoft.VCLibs.x64.14.00.Desktop.appx
+ workingDirectory: $(appxPackageDir)
+
+- task: PowerShell@2
+ displayName: Run Tests Packaged
+ inputs:
+ filePath: 'src\AppInstallerCLITests\Run-TestsInPackage.ps1'
+ arguments: '-Args "~[pips]" -BuildRoot x64\Release -PackageRoot AppInstallerCLIPackage\bin\x64\Release -LogTarget x64\Release\AICLI-Packaged.log -TestResultsTarget x64\Release\TEST-AppInstallerCLI-Packaged.xml -ScriptWait'
+ workingDirectory: 'src'
+
+- task: PublishBuildArtifacts@1
+ displayName: Publish Packaged Log
+ inputs:
+ PathtoPublish: 'src\x64\Release\AICLI-Packaged.log'
+ ArtifactName: 'TestPassPackagedLog'
+ publishLocation: 'Container'
+ condition: succeededOrFailed()
+
+- task: PublishBuildArtifacts@1
+ displayName: Publish Packaged Output
+ inputs:
+ PathtoPublish: 'src\x64\Release\TEST-AppInstallerCLI-Packaged.xml'
+ ArtifactName: 'TestPassPackagedOutput'
publishLocation: 'Container'
condition: succeededOrFailed()
- task: PublishTestResults@2
+ displayName: Publish Test Results
inputs:
testResultsFormat: 'JUnit'
testResultsFiles: '**/TEST-*.xml'
@@ -59,12 +97,14 @@ steps:
condition: succeededOrFailed()
- task: PublishBuildArtifacts@1
+ displayName: Publish CLI Binary
inputs:
PathtoPublish: 'src\x64\Release\AppInstallerCLI\AppInstallerCLI.exe'
ArtifactName: 'AppInstallerCLI.exe'
publishLocation: 'Container'
- task: ComponentGovernanceComponentDetection@0
+ displayName: Component Governance
inputs:
scanType: 'Register'
verbosity: 'Verbose'
diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj
@@ -221,6 +221,7 @@
<CopyFileToFolders Include="TestData\TestSignedApp.msix">
<DeploymentContent>true</DeploymentContent>
</CopyFileToFolders>
+ <None Include="Run-TestsInPackage.ps1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AppInstallerCLICore\AppInstallerCLICore.vcxproj">
diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters
@@ -87,6 +87,7 @@
<ItemGroup>
<None Include="PropertySheet.props" />
<None Include="packages.config" />
+ <None Include="Run-TestsInPackage.ps1" />
</ItemGroup>
<ItemGroup>
<CopyFileToFolders Include="TestData\BadManifest-MissingName.yml">
diff --git a/src/AppInstallerCLITests/Run-TestsInPackage.ps1 b/src/AppInstallerCLITests/Run-TestsInPackage.ps1
@@ -0,0 +1,148 @@
+<#
+.SYNOPSIS
+ Runs the AppInstallerCLI tests within the packaged context.
+.DESCRIPTION
+ Registers the loose files generated by the AppInstallerCLIPackage project, then runs the
+ existing tests from "within" this context.
+.PARAMETER BuildRoot
+ The root of the build output directory. If not provided, assumed to be the local default
+ location relative to this script.
+.PARAMETER PackageRoot
+ The root of the package build output directory. If not provided, assumed to be the local default
+ location relative to this script.
+.PARAMETER LogTarget
+ The file path to log to.
+.PARAMETER TestResultsTarget
+ The file path to place the test result file in.
+.PARAMETER Args
+ Additional args to pass to the tests.
+.PARAMETER Wait
+ Have the test process wait for user input before exiting.
+.PARAMETER ScriptWait
+ Have the script wait for the output files to be freed before exiting.
+#>
+param(
+ [Parameter(Mandatory=$false)]
+ [string]$BuildRoot,
+
+ [Parameter(Mandatory=$false)]
+ [string]$PackageRoot,
+
+ [Parameter(Mandatory=$false)]
+ [string]$LogTarget,
+
+ [Parameter(Mandatory=$false)]
+ [string]$TestResultsTarget,
+
+ [Parameter(Mandatory=$false)]
+ [string]$Args,
+
+ [switch]$Wait,
+
+ [switch]$ScriptWait
+)
+
+function Wait-ForFileClose([string]$Path)
+{
+ $Local:FileInfo = [System.IO.FileInfo]::new($Path)
+ $Local:SleepCount = 0
+
+ while ($Local:SleepCount -lt 300)
+ {
+ try
+ {
+ [System.IO.FileStream] $Local:Stream = $Local:FileInfo.OpenWrite()
+ $Local:Stream.Dispose()
+ break
+ }
+ catch
+ {
+ Start-Sleep 1
+ $Local:SleepCount = $Local:SleepCount + 1
+ }
+ }
+}
+
+if ([String]::IsNullOrEmpty($BuildRoot))
+{
+ $BuildRoot = Split-Path -Parent $PSCommandPath;
+ $BuildRoot = Join-Path $BuildRoot "..\x64\Debug";
+}
+$BuildRoot = Resolve-Path $BuildRoot
+Write-Host "Using BuildRoot = $BuildRoot"
+
+if ([String]::IsNullOrEmpty($PackageRoot))
+{
+ $PackageRoot = Split-Path -Parent $PSCommandPath;
+ $PackageRoot = Join-Path $PackageRoot "..\AppInstallerCLIPackage\bin\x64\Debug";
+}
+$PackageRoot = Resolve-Path $PackageRoot
+Write-Host "Using PackageRoot = $PackageRoot"
+
+if (![String]::IsNullOrEmpty($LogTarget))
+{
+ $Local:temp = Split-Path -Parent $LogTarget
+ $Local:temp = Resolve-Path $Local:temp
+ $LogTarget = Join-Path $Local:temp (Split-Path -Leaf $LogTarget)
+ Write-Host "Using LogTarget = $LogTarget"
+}
+
+if (![String]::IsNullOrEmpty($TestResultsTarget))
+{
+ $Local:temp = Split-Path -Parent $TestResultsTarget
+ $Local:temp = Resolve-Path $Local:temp
+ $TestResultsTarget = Join-Path $Local:temp (Split-Path -Leaf $TestResultsTarget)
+ Write-Host "Using TestResultsTarget = $TestResultsTarget"
+}
+
+# Register the package; this requires the local package to have been deployed at least once or it won't be built.
+$Local:ManifestPath = Join-Path $PackageRoot "AppxManifest.xml"
+if (-not (Test-Path $Local:ManifestPath))
+{
+ $Local:ManifestPath = Join-Path $PackageRoot "AppX\AppxManifest.xml"
+}
+Write-Host "Registering manifest at path: $Local:ManifestPath"
+Add-AppxPackage -Register $Local:ManifestPath
+
+# Execute the tests from within the package's runtime.
+$Local:TestExePath = Join-Path $BuildRoot "AppInstallerCLITests\AppInstallerCLITests.exe"
+$Local:TestArgs = $Args
+
+if ([String]::IsNullOrEmpty($LogTarget))
+{
+ $Local:TestArgs = $Local:TestArgs + " -log"
+}
+else
+{
+ $Local:TestArgs = $Local:TestArgs + " -logto ""$LogTarget"""
+}
+
+if (![String]::IsNullOrEmpty($TestResultsTarget))
+{
+ $Local:TestArgs = $Local:TestArgs + " -s -r junit -o ""$TestResultsTarget"""
+}
+
+if ($Wait)
+{
+ $Local:TestArgs = $Local:TestArgs + " -wait"
+}
+
+Write-Host "Executing tests at path: $Local:TestExePath"
+Write-Host "Executing tests with args: $Local:TestArgs"
+Invoke-CommandInDesktopPackage -PackageFamilyName AppInstallerCLI_8wekyb3d8bbwe -AppId AppInst -Command $Local:TestExePath -Args $Local:TestArgs
+
+if ($ScriptWait)
+{
+ Write-Host "Waiting for output files to be closed..."
+ Start-Sleep 5
+ if (![String]::IsNullOrEmpty($LogTarget))
+ {
+ Wait-ForFileClose $LogTarget
+ }
+
+ if (![String]::IsNullOrEmpty($TestResultsTarget))
+ {
+ Wait-ForFileClose $TestResultsTarget
+ }
+ Write-Host "Done"
+}
diff --git a/src/AppInstallerCLITests/main.cpp b/src/AppInstallerCLITests/main.cpp
@@ -3,6 +3,7 @@
#define CATCH_CONFIG_RUNNER
#include <catch.hpp>
#include <winrt/Windows.Foundation.h>
+#include <iostream>
#include <string>
#include <vector>
@@ -49,6 +50,7 @@ int main(int argc, char** argv)
init_apartment();
bool hasSetTestDataBasePath = false;
+ bool waitBeforeReturn = false;
std::vector<char*> args;
for (int i = 0; i < argc; ++i)
@@ -79,6 +81,10 @@ int main(int argc, char** argv)
hasSetTestDataBasePath = true;
}
}
+ else if ("-wait"s == argv[i])
+ {
+ waitBeforeReturn = true;
+ }
else
{
args.push_back(argv[i]);
@@ -108,5 +114,13 @@ int main(int argc, char** argv)
// This prevents test runs from trashing the users actual settings.
AppInstaller::Runtime::TestHook_ForceContainerPrepend("AutoTestContainer");
- return Catch::Session().run(static_cast<int>(args.size()), args.data());
+ int result = Catch::Session().run(static_cast<int>(args.size()), args.data());
+
+ if (waitBeforeReturn)
+ {
+ // Wait for some input before returning
+ std::cin.get();
+ }
+
+ return result;
}
diff --git a/src/AppInstallerCommonCore/Deployment.cpp b/src/AppInstallerCommonCore/Deployment.cpp
@@ -56,7 +56,8 @@ namespace AppInstaller::Deployment
{
AICLI_LOG(Core, Error, << "Deployment failed #" << id << ": " << Utility::ConvertToUTF8(deployResult.ErrorText()));
- THROW_HR_MSG(deployResult.ExtendedErrorCode(), "Install failed: %s", Utility::ConvertToUTF8(deployResult.ErrorText()).c_str());
+ // Note that while the format string is char*, it gets converted to wchar before being used and thus %s needs a wchar.
+ THROW_HR_MSG(deployResult.ExtendedErrorCode(), "Install failed: %s", deployResult.ErrorText().c_str());
}
else
{