commit 95f504f4bcd1fbfc0033b68629ce42344e722dfc parent 827a43af1a9c25b64c748e5064afaa7603f05229 Author: Ryan Fu <69221034+ryfu-msft@users.noreply.github.com> Date: Tue, 22 Sep 2020 14:01:28 -0700 Integrate Localhost Web Server for Install Command Testing (#543) * Testing out Git * Refactored Install Command Testing Code and Added Local FilePaths to Testing Source, which will need to be removed later * Serve static files through local https for testing * Refactored Tests * Added TextSupport Tests for GR * Added Command Line Parameter to begin localhosting for E2ETests * Updated Azure-Pipeline build to launch kestrel server & fixed Global Readiness to check Manifest Name * Edited files prep for Pull Request * Changed Name to CharacterHandling Tests * Removed Readme File * Updated Validate Command * Updated Validate Command * Removed Duplicate Pipeline Tasks * Merge Conflicts * Changed Architecture for pipeline * reverted changes to wapproj file * Added setup to generate hash for testing installers and for replacing manifests with newly created hash values * Refactored LaunchKestrel * added powershell script to setup and launch kestrel app * refactored testing logic and added methods to create local testing index for creating index from testing manifests * automated testing directory setup * Added methods to setup test directory in TEMP to be served as localindex * added indexhostservice to azure pipeline * removed semi-colon * added IndexHostService and removed LaunchKestrel * changed working directory to match indexhostservice * Edited build pipeline for launching indexhostservice * added powershell task * edited ps script * added arguments to PS script * added missing comma + extra msi and msix param) * fixed path to indexhost service * run indexhostservice in background task * added missing hyphen * copy wingetutil.dll to indexcreation path before running tests * Added Console output for debugging * added static file root parameter to test setup * fixed azure pipeline parameter for static file root * edited setup for tests * added cert to kestrel * added cert to kestrel * updated indexhostservice powershell script * added kestrel certificate config * changed build root * fixed param * install cert root path * secureFilPath HTTPSDevCert * reverted back to exe start process * output directory * add sign package * added HRESULT for http * edited error HRESULT output and added published logs for E2E Test * edited manifest path and updated logs for e2E tests * added log lines * testing kestrel server * revert powershell script to start-process background * testing no index task * added index page for localhost * fix powershell command * change content root path * seed files * test source add * test * test source add * run kestrel in e2E tests * added web request * write host invoke web request * created package in testlocalindex * added logs for filepath * added makeappx path * signtool fix * signed exe installer * modified command tests * removed MOTW functionality * removed line * renamed to LocalhostWebServer * removed indexhostservice files * refactored hashing methods * refactored and added WINGET_DISABLE_MOTW * added quotes to windows sdk path * dWingetDisable * azp define * /D * added preprocessing * added env var * define constant * externalcompiler * added registry keys for filetyperestrictions * zoneinformation * removed zoneinfo and decreased filetype risk * consume msixutils and refactored * cleaned up extra lines, and renamed index -> directory * removed AppInstallerCLI.exe files * Added CLI parsing for LocalHostWebServer * dynamically generates Signature Hash * Fixed multiple apps found test * changed package extraction to temp folder * changed testID conflict with TestValidManifest.yaml * testing makeappx * revert to only EXE * hardcoded SDK bin path * corrected SDK path * removed itemgroup * testing makeappx + indexcreationtool * added working directory to indexcreationtool * verify if indexdestpath is valid before running * cleaned up unnecessary code * integrate MSIX E2E tests with pipeline * add parameter for MSIX * updated read in setup and azp pipeline build * revert MSIX tests * removed anycpu and win32 arch * edited pipeline to reflect new arch * removed AnyCPU arch from localhostwebserver * launch localhost x86 Diffstat:
54 files changed, 1569 insertions(+), 640 deletions(-)
diff --git a/azure-pipelines.yml b/azure-pipelines.yml @@ -1,272 +1,304 @@ -# Commit triggers -trigger: -- master - -# PR triggers -pr: - branches: - include: - - master - paths: - include: - - azure-pipelines.yml - - src/* - -pool: - vmImage: 'windows-latest' - -variables: - solution: 'src/AppInstallerCLI.sln' - buildPlatform: 'x86|x64|ARM' - buildConfiguration: 'Release' - appxPackageDir: '$(build.artifactStagingDirectory)\AppxPackages\\' - -# Do not set the build version for a PR build. - -jobs: -- job: 'GetReleaseTag' - condition: not(eq(variables['Build.Reason'], 'PullRequest')) - variables: - runCodesignValidationInjection: ${{ false }} - skipComponentGovernanceDetection: ${{ true }} - steps: - - task: PowerShell@2 - name: 'GetTag' - displayName: Get Release Tag - inputs: - filePath: 'src\binver\Update-BinVer.ps1' - arguments: '-OutVar' - workingDirectory: 'src' - -- job: 'Build' - dependsOn: 'GetReleaseTag' - condition: always() - variables: - BuildVer: $[counter(dependencies.GetReleaseTag.outputs['GetTag.tag'], 1)] - steps: - - task: NuGetToolInstaller@1 - displayName: Install Nuget - - - task: NuGetCommand@2 - displayName: Restore Packages - inputs: - restoreSolution: '$(solution)' - - - task: DotNetCoreCLI@2 - displayName: DotNet Restore - inputs: - command: 'restore' - projects: '**/*.csproj' - - - task: PowerShell@2 - displayName: Update Binary Version - condition: not(eq(variables['Build.Reason'], 'PullRequest')) - inputs: - filePath: 'src\binver\Update-BinVer.ps1' - arguments: '-TargetFile binver\binver\version.h -BuildVersion $(BuildVer)' - workingDirectory: 'src' - - - task: VSBuild@1 - displayName: Build Solution - inputs: - platform: 'x86' - solution: '$(solution)' - configuration: '$(buildConfiguration)' - msbuildArgs: '/p:AppxBundlePlatforms="$(buildPlatform)" - /p:AppxPackageDir="$(appxPackageDir)" - /p:AppxBundle=Always - /p:UapAppxPackageBuildMode=StoreUpload' - - - task: PowerShell@2 - displayName: Install Tests Dependencies - inputs: - targetType: 'inline' - script: | - Add-AppxPackage AppInstallerCLIPackage_0.0.2.0_Test\Dependencies\x86\Microsoft.VCLibs.x86.14.00.Desktop.appx - Add-AppxPackage AppInstallerCLIPackage_0.0.2.0_Test\Dependencies\x64\Microsoft.VCLibs.x64.14.00.Desktop.appx - workingDirectory: $(appxPackageDir) - - - task: VisualStudioTestPlatformInstaller@1 - displayName: Prepare VSTest for E2E Tests - inputs: - packageFeedSelector: 'nugetOrg' - -# TODO: Convert tests to run based on the whether things have worked up to this point - -# - task: CmdLine@2 -# displayName: Run Unit Tests Unpackaged x64 -# inputs: -# script: | -# AppInstallerCLITests.exe -logto AICLI-Unpackaged-x64.log -s -r junit -o TEST-AppInstallerCLI-Unpackaged-x64.xml -# workingDirectory: 'src\x64\Release\AppInstallerCLITests\' -# condition: succeededOrFailed() - -# - task: PublishBuildArtifacts@1 -# displayName: Publish Unit Tests Unpackaged Log x64 -# inputs: -# PathtoPublish: 'src\x64\Release\AppInstallerCLITests\AICLI-Unpackaged-x64.log' -# ArtifactName: 'TestPassUnpackagedLog' -# publishLocation: 'Container' -# condition: succeededOrFailed() - -# - task: PublishBuildArtifacts@1 -# displayName: Publish Unit Tests Unpackaged Output x64 -# inputs: -# PathtoPublish: 'src\x64\Release\AppInstallerCLITests\TEST-AppInstallerCLI-Unpackaged-x64.xml' -# ArtifactName: 'TestPassUnpackagedOutput' -# publishLocation: 'Container' -# condition: succeededOrFailed() - - - task: PowerShell@2 - displayName: Run Unit Tests Packaged x64 - inputs: - filePath: 'src\AppInstallerCLITests\Run-TestsInPackage.ps1' - arguments: '-Args "~[pips]" -BuildRoot x64\Release -PackageRoot AppInstallerCLIPackage\bin\x64\Release -LogTarget x64\Release\AICLI-Packaged-x64.log -TestResultsTarget x64\Release\TEST-AppInstallerCLI-Packaged-x64.xml -ScriptWait' - workingDirectory: 'src' - condition: succeededOrFailed() - - - task: PublishBuildArtifacts@1 - displayName: Publish Unit Tests Packaged Log x64 - inputs: - PathtoPublish: 'src\x64\Release\AICLI-Packaged-x64.log' - ArtifactName: 'TestPassPackagedLog' - publishLocation: 'Container' - condition: succeededOrFailed() - - - task: PublishBuildArtifacts@1 - displayName: Publish Unit Tests Packaged Output x64 - inputs: - PathtoPublish: 'src\x64\Release\TEST-AppInstallerCLI-Packaged-x64.xml' - ArtifactName: 'TestPassPackagedOutput' - publishLocation: 'Container' - condition: succeededOrFailed() - -# - task: CmdLine@2 -# displayName: Run Unit Tests Unpackaged x86 -# inputs: -# script: | -# AppInstallerCLITests.exe -logto AICLI-Unpackaged-x86.log -s -r junit -o TEST-AppInstallerCLI-Unpackaged-x86.xml -# workingDirectory: 'src\x86\Release\AppInstallerCLITests\' -# condition: succeededOrFailed() - -# - task: PublishBuildArtifacts@1 -# displayName: Publish Unit Tests Unpackaged Log x86 -# inputs: -# PathtoPublish: 'src\x86\Release\AppInstallerCLITests\AICLI-Unpackaged-x86.log' -# ArtifactName: 'TestPassUnpackagedLog' -# publishLocation: 'Container' -# condition: succeededOrFailed() - -# - task: PublishBuildArtifacts@1 -# displayName: Publish Unit Tests Unpackaged Output x86 -# inputs: -# PathtoPublish: 'src\x86\Release\AppInstallerCLITests\TEST-AppInstallerCLI-Unpackaged-x86.xml' -# ArtifactName: 'TestPassUnpackagedOutput' -# publishLocation: 'Container' -# condition: succeededOrFailed() - - - task: PowerShell@2 - displayName: Run Unit Tests Packaged x86 - inputs: - filePath: 'src\AppInstallerCLITests\Run-TestsInPackage.ps1' - arguments: '-Args "~[pips]" -BuildRoot x86\Release -PackageRoot AppInstallerCLIPackage\bin\x86\Release -LogTarget x86\Release\AICLI-Packaged-x86.log -TestResultsTarget x86\Release\TEST-AppInstallerCLI-Packaged-x86.xml -ScriptWait' - workingDirectory: 'src' - condition: succeededOrFailed() - - - task: PublishBuildArtifacts@1 - displayName: Publish Unit Tests Packaged Log x86 - inputs: - PathtoPublish: 'src\x86\Release\AICLI-Packaged-x86.log' - ArtifactName: 'TestPassPackagedLog' - publishLocation: 'Container' - condition: succeededOrFailed() - - - task: PublishBuildArtifacts@1 - displayName: Publish Unit Tests Packaged Output x86 - inputs: - PathtoPublish: 'src\x86\Release\TEST-AppInstallerCLI-Packaged-x86.xml' - ArtifactName: 'TestPassPackagedOutput' - publishLocation: 'Container' - condition: succeededOrFailed() - - - task: PublishTestResults@2 - displayName: Publish Unit Test Results - inputs: - testResultsFormat: 'JUnit' - testResultsFiles: '**/TEST-*.xml' - failTaskOnFailedTests: true - condition: succeededOrFailed() - -# - task: VSTest@2 -# displayName: Run E2E Tests Unpackaged x64 -# inputs: -# testSelector: 'testAssemblies' -# testAssemblyVer2: 'src\x64\Release\AppInstallerCLIE2ETests\AppInstallerCLIE2ETests.dll' -# runSettingsFile: 'src\x64\Release\AppInstallerCLIE2ETests\Test.runsettings' -# overrideTestrunParameters: '-PackagedContext false -# -AICLIPath $(system.defaultWorkingDirectory)\src\x64\Release\AppInstallerCLI\AppInstallerCLI.exe' -# condition: succeededOrFailed() - - - task: VSTest@2 - displayName: Run E2E Tests Packaged x64 - inputs: - testSelector: 'testAssemblies' - testAssemblyVer2: 'src\x64\Release\AppInstallerCLIE2ETests\AppInstallerCLIE2ETests.dll' - runSettingsFile: 'src\x64\Release\AppInstallerCLIE2ETests\Test.runsettings' - overrideTestrunParameters: '-PackagedContext true - -AICLIPackagePath $(system.defaultWorkingDirectory)\src\AppInstallerCLIPackage\bin\x64\Release - -AICLIPath AppInstallerCLI\AppInstallerCLI.exe - -LooseFileRegistration true - -InvokeCommandInDesktopPackage true' - condition: succeededOrFailed() - -# - task: VSTest@2 -# displayName: Run E2E Tests Unpackaged x86 -# inputs: -# testSelector: 'testAssemblies' -# testAssemblyVer2: 'src\x86\Release\AppInstallerCLIE2ETests\AppInstallerCLIE2ETests.dll' -# runSettingsFile: 'src\x86\Release\AppInstallerCLIE2ETests\Test.runsettings' -# overrideTestrunParameters: '-PackagedContext false -# -AICLIPath $(system.defaultWorkingDirectory)\src\x86\Release\AppInstallerCLI\AppInstallerCLI.exe' -# condition: succeededOrFailed() - - - task: VSTest@2 - displayName: Run E2E Tests Packaged x86 - inputs: - testSelector: 'testAssemblies' - testAssemblyVer2: 'src\x86\Release\AppInstallerCLIE2ETests\AppInstallerCLIE2ETests.dll' - runSettingsFile: 'src\x86\Release\AppInstallerCLIE2ETests\Test.runsettings' - overrideTestrunParameters: '-PackagedContext true - -AICLIPackagePath $(system.defaultWorkingDirectory)\src\AppInstallerCLIPackage\bin\x86\Release - -AICLIPath AppInstallerCLI\AppInstallerCLI.exe - -LooseFileRegistration true - -InvokeCommandInDesktopPackage true' - condition: succeededOrFailed() - - - task: PublishBuildArtifacts@1 - displayName: Publish CLI Binary - inputs: - PathtoPublish: 'src\x64\Release\AppInstallerCLI\AppInstallerCLI.exe' - ArtifactName: 'AppInstallerCLI.exe' - publishLocation: 'Container' - - - task: PublishBuildArtifacts@1 - displayName: Publish Util Binary - inputs: - PathtoPublish: 'src\x64\Release\WinGetUtil\WinGetUtil.dll' - ArtifactName: 'WinGetUtil.dll' - publishLocation: 'Container' - - - task: PublishBuildArtifacts@1 - displayName: Publish Util Symbols - inputs: - PathtoPublish: 'src\x64\Release\WinGetUtil\WinGetUtil.pdb' - ArtifactName: 'WinGetUtil.pdb' - publishLocation: 'Container' - - - task: ComponentGovernanceComponentDetection@0 - displayName: Component Governance - inputs: - scanType: 'Register' - verbosity: 'Verbose' +# Commit triggers +trigger: +- master + +# PR triggers +pr: + branches: + include: + - master + paths: + include: + - azure-pipelines.yml + - src/* + +pool: + vmImage: 'windows-latest' + +variables: + solution: 'src/AppInstallerCLI.sln' + buildPlatform: 'x86|x64|ARM' + buildConfiguration: 'Release' + appxPackageDir: '$(build.artifactStagingDirectory)\AppxPackages\\' + +# Do not set the build version for a PR build. + +jobs: +- job: 'GetReleaseTag' + condition: not(eq(variables['Build.Reason'], 'PullRequest')) + variables: + runCodesignValidationInjection: ${{ false }} + skipComponentGovernanceDetection: ${{ true }} + steps: + - task: PowerShell@2 + name: 'GetTag' + displayName: Get Release Tag + inputs: + filePath: 'src\binver\Update-BinVer.ps1' + arguments: '-OutVar' + workingDirectory: 'src' + +- job: 'Build' + dependsOn: 'GetReleaseTag' + condition: always() + variables: + BuildVer: $[counter(dependencies.GetReleaseTag.outputs['GetTag.tag'], 1)] + steps: + - task: NuGetToolInstaller@1 + displayName: Install Nuget + + - task: NuGetCommand@2 + displayName: Restore Packages + inputs: + restoreSolution: '$(solution)' + + - task: DotNetCoreCLI@2 + displayName: DotNet Restore + inputs: + command: 'restore' + projects: '**/*.csproj' + + - task: PowerShell@2 + displayName: Update Binary Version + condition: not(eq(variables['Build.Reason'], 'PullRequest')) + inputs: + filePath: 'src\binver\Update-BinVer.ps1' + arguments: '-TargetFile binver\binver\version.h -BuildVersion $(BuildVer)' + workingDirectory: 'src' + + - task: VSBuild@1 + displayName: Build Solution + inputs: + platform: 'x86' + solution: '$(solution)' + configuration: '$(buildConfiguration)' + msbuildArgs: '/p:AppxBundlePlatforms="$(buildPlatform)" + /p:AppxPackageDir="$(appxPackageDir)" + /p:AppxBundle=Always + /p:UapAppxPackageBuildMode=StoreUpload' + + - task: PowerShell@2 + displayName: Install Tests Dependencies + inputs: + targetType: 'inline' + script: | + Add-AppxPackage AppInstallerCLIPackage_0.0.2.0_Test\Dependencies\x86\Microsoft.VCLibs.x86.14.00.Desktop.appx + Add-AppxPackage AppInstallerCLIPackage_0.0.2.0_Test\Dependencies\x64\Microsoft.VCLibs.x64.14.00.Desktop.appx + workingDirectory: $(appxPackageDir) + + - task: VisualStudioTestPlatformInstaller@1 + displayName: Prepare VSTest for E2E Tests + inputs: + packageFeedSelector: 'nugetOrg' + +# TODO: Convert tests to run based on the whether things have worked up to this point + +# - task: CmdLine@2 +# displayName: Run Unit Tests Unpackaged x64 +# inputs: +# script: | +# AppInstallerCLITests.exe -logto AICLI-Unpackaged-x64.log -s -r junit -o TEST-AppInstallerCLI-Unpackaged-x64.xml +# workingDirectory: 'src\x64\Release\AppInstallerCLITests\' +# condition: succeededOrFailed() + +# - task: PublishBuildArtifacts@1 +# displayName: Publish Unit Tests Unpackaged Log x64 +# inputs: +# PathtoPublish: 'src\x64\Release\AppInstallerCLITests\AICLI-Unpackaged-x64.log' +# ArtifactName: 'TestPassUnpackagedLog' +# publishLocation: 'Container' +# condition: succeededOrFailed() + +# - task: PublishBuildArtifacts@1 +# displayName: Publish Unit Tests Unpackaged Output x64 +# inputs: +# PathtoPublish: 'src\x64\Release\AppInstallerCLITests\TEST-AppInstallerCLI-Unpackaged-x64.xml' +# ArtifactName: 'TestPassUnpackagedOutput' +# publishLocation: 'Container' +# condition: succeededOrFailed() + + - task: PowerShell@2 + displayName: Run Unit Tests Packaged x64 + inputs: + filePath: 'src\AppInstallerCLITests\Run-TestsInPackage.ps1' + arguments: '-Args "~[pips]" -BuildRoot x64\Release -PackageRoot AppInstallerCLIPackage\bin\x64\Release -LogTarget x64\Release\AICLI-Packaged-x64.log -TestResultsTarget x64\Release\TEST-AppInstallerCLI-Packaged-x64.xml -ScriptWait' + workingDirectory: 'src' + condition: succeededOrFailed() + + - task: PublishBuildArtifacts@1 + displayName: Publish Unit Tests Packaged Log x64 + inputs: + PathtoPublish: 'src\x64\Release\AICLI-Packaged-x64.log' + ArtifactName: 'TestPassPackagedLog' + publishLocation: 'Container' + condition: succeededOrFailed() + + - task: PublishBuildArtifacts@1 + displayName: Publish Unit Tests Packaged Output x64 + inputs: + PathtoPublish: 'src\x64\Release\TEST-AppInstallerCLI-Packaged-x64.xml' + ArtifactName: 'TestPassPackagedOutput' + publishLocation: 'Container' + condition: succeededOrFailed() + +# - task: CmdLine@2 +# displayName: Run Unit Tests Unpackaged x86 +# inputs: +# script: | +# AppInstallerCLITests.exe -logto AICLI-Unpackaged-x86.log -s -r junit -o TEST-AppInstallerCLI-Unpackaged-x86.xml +# workingDirectory: 'src\x86\Release\AppInstallerCLITests\' +# condition: succeededOrFailed() + +# - task: PublishBuildArtifacts@1 +# displayName: Publish Unit Tests Unpackaged Log x86 +# inputs: +# PathtoPublish: 'src\x86\Release\AppInstallerCLITests\AICLI-Unpackaged-x86.log' +# ArtifactName: 'TestPassUnpackagedLog' +# publishLocation: 'Container' +# condition: succeededOrFailed() + +# - task: PublishBuildArtifacts@1 +# displayName: Publish Unit Tests Unpackaged Output x86 +# inputs: +# PathtoPublish: 'src\x86\Release\AppInstallerCLITests\TEST-AppInstallerCLI-Unpackaged-x86.xml' +# ArtifactName: 'TestPassUnpackagedOutput' +# publishLocation: 'Container' +# condition: succeededOrFailed() + + - task: PowerShell@2 + displayName: Run Unit Tests Packaged x86 + inputs: + filePath: 'src\AppInstallerCLITests\Run-TestsInPackage.ps1' + arguments: '-Args "~[pips]" -BuildRoot x86\Release -PackageRoot AppInstallerCLIPackage\bin\x86\Release -LogTarget x86\Release\AICLI-Packaged-x86.log -TestResultsTarget x86\Release\TEST-AppInstallerCLI-Packaged-x86.xml -ScriptWait' + workingDirectory: 'src' + condition: succeededOrFailed() + + - task: PublishBuildArtifacts@1 + displayName: Publish Unit Tests Packaged Log x86 + inputs: + PathtoPublish: 'src\x86\Release\AICLI-Packaged-x86.log' + ArtifactName: 'TestPassPackagedLog' + publishLocation: 'Container' + condition: succeededOrFailed() + + - task: PublishBuildArtifacts@1 + displayName: Publish Unit Tests Packaged Output x86 + inputs: + PathtoPublish: 'src\x86\Release\TEST-AppInstallerCLI-Packaged-x86.xml' + ArtifactName: 'TestPassPackagedOutput' + publishLocation: 'Container' + condition: succeededOrFailed() + + - task: PublishTestResults@2 + displayName: Publish Unit Test Results + inputs: + testResultsFormat: 'JUnit' + testResultsFiles: '**/TEST-*.xml' + failTaskOnFailedTests: true + condition: succeededOrFailed() + + - task: DownloadSecureFile@1 + name: AppInstallerTest + displayName: 'Download Source Package Certificate' + inputs: + secureFile: 'AppInstallerTest.pfx' + + - task: DownloadSecureFile@1 + name: HTTPSDevCert + displayName: 'Download Kestrel Certificate' + inputs: + secureFile: 'HTTPSDevCert.pfx' + + - task: PowerShell@2 + displayName: Install Root Certificate + inputs: + filePath: 'src\LocalhostWebServer\InstallDevCert.ps1' + arguments: '-pfxpath $(HTTPSDevCert.secureFilePath) -password microsoft' + condition: succeededOrFailed() + + - task: PowerShell@2 + displayName: Launch LocalhostWebServer + inputs: + filePath: 'src\LocalhostWebServer\Run-LocalhostWebServer.ps1' + arguments: '-BuildRoot $(system.defaultWorkingDirectory)\src\x86\Release\LocalhostWebServer -StaticFileRoot $(Agent.TempDirectory)\TestLocalIndex -CertPath $(HTTPSDevCert.secureFilePath) -CertPassword microsoft' + condition: succeededOrFailed() + +# - task: VSTest@2 +# displayName: Run E2E Tests Unpackaged x64 +# inputs: +# testSelector: 'testAssemblies' +# testAssemblyVer2: 'src\x64\Release\AppInstallerCLIE2ETests\AppInstallerCLIE2ETests.dll' +# runSettingsFile: 'src\x64\Release\AppInstallerCLIE2ETests\Test.runsettings' +# overrideTestrunParameters: '-PackagedContext false +# -AICLIPath $(system.defaultWorkingDirectory)\src\x64\Release\AppInstallerCLI\AppInstallerCLI.exe' +# condition: succeededOrFailed() + + - task: VSTest@2 + displayName: Run E2E Tests Packaged x64 + inputs: + testSelector: 'testAssemblies' + testAssemblyVer2: 'src\x64\Release\AppInstallerCLIE2ETests\AppInstallerCLIE2ETests.dll' + runSettingsFile: 'src\x64\Release\AppInstallerCLIE2ETests\Test.runsettings' + overrideTestrunParameters: '-PackagedContext true + -AICLIPackagePath $(system.defaultWorkingDirectory)\src\AppInstallerCLIPackage\bin\x64\Release + -AICLIPath AppInstallerCLI\AppInstallerCLI.exe + -LooseFileRegistration true + -InvokeCommandInDesktopPackage true + -StaticFileRootPath $(Agent.TempDirectory)\TestLocalIndex + -ExeTestInstallerPath $(system.defaultWorkingDirectory)\src\x64\Release\AppInstallerTestExeInstaller\AppInstallerTestExeInstaller.exe + -PackageCertificatePath $(AppInstallerTest.secureFilePath)' + condition: succeededOrFailed() + +# - task: VSTest@2 +# displayName: Run E2E Tests Unpackaged x86 +# inputs: +# testSelector: 'testAssemblies' +# testAssemblyVer2: 'src\x86\Release\AppInstallerCLIE2ETests\AppInstallerCLIE2ETests.dll' +# runSettingsFile: 'src\x86\Release\AppInstallerCLIE2ETests\Test.runsettings' +# overrideTestrunParameters: '-PackagedContext false +# -AICLIPath $(system.defaultWorkingDirectory)\src\x86\Release\AppInstallerCLI\AppInstallerCLI.exe' +# condition: succeededOrFailed() + + - task: VSTest@2 + displayName: Run E2E Tests Packaged x86 + inputs: + testSelector: 'testAssemblies' + testAssemblyVer2: 'src\x86\Release\AppInstallerCLIE2ETests\AppInstallerCLIE2ETests.dll' + runSettingsFile: 'src\x86\Release\AppInstallerCLIE2ETests\Test.runsettings' + overrideTestrunParameters: '-PackagedContext true + -AICLIPackagePath $(system.defaultWorkingDirectory)\src\AppInstallerCLIPackage\bin\x86\Release + -AICLIPath AppInstallerCLI\AppInstallerCLI.exe + -LooseFileRegistration true + -InvokeCommandInDesktopPackage true + -StaticFileRootPath $(Agent.TempDirectory)\TestLocalIndex + -ExeTestInstallerPath $(system.defaultWorkingDirectory)\src\x86\Release\AppInstallerTestExeInstaller\AppInstallerTestExeInstaller.exe + -PackageCertificatePath $(AppInstallerTest.secureFilePath)' + condition: succeededOrFailed() + + - task: PublishBuildArtifacts@1 + displayName: Publish CLI Binary + inputs: + PathtoPublish: 'src\x64\Release\AppInstallerCLI\AppInstallerCLI.exe' + ArtifactName: 'AppInstallerCLI.exe' + publishLocation: 'Container' + + - task: PublishBuildArtifacts@1 + displayName: Publish Util Binary + inputs: + PathtoPublish: 'src\x64\Release\WinGetUtil\WinGetUtil.dll' + ArtifactName: 'WinGetUtil.dll' + publishLocation: 'Container' + + - task: PublishBuildArtifacts@1 + displayName: Publish Util Symbols + inputs: + PathtoPublish: 'src\x64\Release\WinGetUtil\WinGetUtil.pdb' + ArtifactName: 'WinGetUtil.pdb' + publishLocation: 'Container' + + - task: ComponentGovernanceComponentDetection@0 + displayName: Component Governance + inputs: + scanType: 'Register' + verbosity: 'Verbose' alertWarningLevel: 'High' \ No newline at end of file diff --git a/src/AppInstallerCLI.sln b/src/AppInstallerCLI.sln @@ -39,6 +39,11 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "binver", "binver\binver.vcxitems", "{6E36DDD7-1602-474E-B1D7-D0A7E1D5AD86}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppInstallerCLIE2ETests", "AppInstallerCLIE2ETests\AppInstallerCLIE2ETests.csproj", "{3C0269FA-E582-4CA7-9E33-3881A005CA0C}" + ProjectSection(ProjectDependencies) = postProject + {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8} = {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8} + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA} = {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA} + {6CB84692-5994-407D-B9BD-9216AF77FE83} = {6CB84692-5994-407D-B9BD-9216AF77FE83} + EndProjectSection EndProject Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "AppInstallerTestMsixInstaller", "AppInstallerTestMsixInstaller\AppInstallerTestMsixInstaller.wapproj", "{3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}" EndProject @@ -54,6 +59,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Fuzzing", "Fuzzing", "{6D77 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WinGetYamlFuzzing", "WinGetYamlFuzzing\WinGetYamlFuzzing.vcxproj", "{1622DA16-914F-4F57-A259-D5169003CC8C}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LocalhostWebServer", "LocalhostWebServer\LocalhostWebServer.csproj", "{3BAF989F-7F65-465B-ACE8-BAFE42D1017E}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution catch2\catch2.vcxitems*{5295e21e-9868-4de2-a177-fbb97b36579b}*SharedItemsImports = 9 @@ -310,6 +317,7 @@ Global {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Debug|ARM.ActiveCfg = Debug {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Debug|ARM64.ActiveCfg = Debug {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Debug|x64.ActiveCfg = Debug + {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Debug|x64.Build.0 = Debug {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Debug|x86.ActiveCfg = Debug {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Fuzzing|ARM.ActiveCfg = Release {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Fuzzing|ARM64.ActiveCfg = Release @@ -319,6 +327,7 @@ Global {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Release|ARM64.ActiveCfg = Release {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Release|x64.ActiveCfg = Release {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Release|x86.ActiveCfg = Release + {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Release|x86.Build.0 = Release {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Debug|ARM.ActiveCfg = Debug|x86 {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Debug|ARM64.ActiveCfg = Debug|x86 {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Debug|x64.ActiveCfg = Debug|x64 @@ -368,6 +377,30 @@ Global {1622DA16-914F-4F57-A259-D5169003CC8C}.Release|ARM64.ActiveCfg = Fuzzing|x64 {1622DA16-914F-4F57-A259-D5169003CC8C}.Release|x64.ActiveCfg = Fuzzing|x64 {1622DA16-914F-4F57-A259-D5169003CC8C}.Release|x86.ActiveCfg = Fuzzing|x64 + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Debug|ARM.ActiveCfg = Debug|x86 + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Debug|ARM.Build.0 = Debug|x86 + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Debug|ARM64.ActiveCfg = Debug|x86 + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Debug|ARM64.Build.0 = Debug|x86 + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Debug|x64.ActiveCfg = Debug|x64 + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Debug|x64.Build.0 = Debug|x64 + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Debug|x86.ActiveCfg = Debug|x86 + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Debug|x86.Build.0 = Debug|x86 + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Fuzzing|ARM.ActiveCfg = Debug|Any CPU + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Fuzzing|ARM.Build.0 = Debug|Any CPU + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Fuzzing|ARM64.ActiveCfg = Debug|Any CPU + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Fuzzing|ARM64.Build.0 = Debug|Any CPU + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Fuzzing|x64.ActiveCfg = Debug|Any CPU + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Fuzzing|x64.Build.0 = Debug|Any CPU + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Fuzzing|x86.ActiveCfg = Debug|Any CPU + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Fuzzing|x86.Build.0 = Debug|Any CPU + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Release|ARM.ActiveCfg = Release|x86 + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Release|ARM.Build.0 = Release|x86 + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Release|ARM64.ActiveCfg = Release|x86 + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Release|ARM64.Build.0 = Release|x86 + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Release|x64.ActiveCfg = Release|x64 + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Release|x64.Build.0 = Release|x64 + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Release|x86.ActiveCfg = Release|x86 + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -379,6 +412,7 @@ Global {3B8466CF-4FDD-4329-9C80-91321C4AAC99} = {EA8CD934-0702-4911-A2C5-A40600E616DE} {82B39FDA-E86B-4713-A873-9D56DE00247A} = {60618CAC-2995-4DF9-9914-45C6FC02C995} {1622DA16-914F-4F57-A259-D5169003CC8C} = {6D7776A8-42FE-46DD-B0F8-712F35EA0C79} + {3BAF989F-7F65-465B-ACE8-BAFE42D1017E} = {EA8CD934-0702-4911-A2C5-A40600E616DE} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B6FDB70C-A751-422C-ACD1-E35419495857} diff --git a/src/AppInstallerCLIE2ETests/AppInstallerCLIE2ETests.csproj b/src/AppInstallerCLIE2ETests/AppInstallerCLIE2ETests.csproj @@ -1,13 +1,15 @@ -<Project Sdk="Microsoft.NET.Sdk"> +<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework> <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\AppInstallerCLIE2ETests\</OutDir> <IsPackable>false</IsPackable> <Platforms>x64;x86</Platforms> + <OutputType>Library</OutputType> </PropertyGroup> <ItemGroup> + <PackageReference Include="Microsoft.Msix.Utils" Version="1.0.200812001" /> <PackageReference Include="Microsoft.Win32.Registry" Version="4.7.0" /> <PackageReference Include="nunit" Version="3.12.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.15.1" /> @@ -21,6 +23,10 @@ </ItemGroup> <ItemGroup> + <ProjectReference Include="..\IndexCreationTool\IndexCreationTool.csproj" /> + </ItemGroup> + + <ItemGroup> <None Update="Test.runsettings"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> diff --git a/src/AppInstallerCLIE2ETests/Constants.cs b/src/AppInstallerCLIE2ETests/Constants.cs @@ -12,7 +12,11 @@ namespace AppInstallerCLIE2ETests public const string VerboseLoggingParameter = "VerboseLogging"; public const string LooseFileRegistrationParameter = "LooseFileRegistration"; public const string InvokeCommandInDesktopPackageParameter = "InvokeCommandInDesktopPackage"; - + public const string StaticFileRootPathParameter = "StaticFileRootPath"; + public const string ExeInstallerPathParameter = "ExeTestInstallerPath"; + public const string MsiInstallerPathParameter = "MsiTestInstallerPath"; + public const string MsixInstallerPathParameter = "MsixTestInstallerPath"; + public const string PackageCertificatePathParameter = "PackageCertificatePath"; public const string AppInstallerTestCert = "AppInstallerTest.cer"; public const string AppInstallerTestCertThumbprint = "d03e7a688b388b1edde8476a627531c49db88017"; @@ -25,6 +29,14 @@ namespace AppInstallerCLIE2ETests public const string AICLIAppId = "WinGetDev"; public const string TestPackage = "TëstPackage.msix"; + public const string ExeInstaller = "AppInstallerTestExeInstaller"; + public const string MsiInstaller = "AppInstallerTestMsiInstaller"; + public const string MsixInstaller = "AppInstallerTestMsixInstaller"; + public const string IndexPackage = "source.msix"; + public const string MakeAppx = "makeappx.exe"; + public const string SignTool = "signtool.exe"; + public const string IndexCreationTool = "IndexCreationTool"; + public const string WinGetUtil = "WinGetUtil"; public class ErrorCode { diff --git a/src/AppInstallerCLIE2ETests/HashCommand.cs b/src/AppInstallerCLIE2ETests/HashCommand.cs @@ -8,27 +8,36 @@ namespace AppInstallerCLIE2ETests public class HashCommand { [Test] - public void HashCommands() + public void HashFile() { - // Hash a file var result = TestCommon.RunAICLICommand("hash", TestCommon.GetTestDataFile("AppInstallerTest.cer")); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); Assert.True(result.StdOut.Contains("9b4c49ad7e47afd97d2e666e93347745e1647c55f1a7ebba6d31b7dd5f69ee68")); + } - // Hash msix - result = TestCommon.RunAICLICommand("hash", TestCommon.GetTestDataFile(Constants.TestPackage) + " -m"); + [Test] + public void HashMSIX() + { + var result = TestCommon.RunAICLICommand("hash", TestCommon.GetTestDataFile(Constants.TestPackage) + " -m"); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); Assert.True(result.StdOut.Contains("08917b781939a7796746b5e2349e1f1d83b6c15599b60cd3f62816f15e565fc4")); Assert.True(result.StdOut.Contains("223b318c4b1154a1fb72b1bc23422810faa5ce899a8e774ba2a02834b2058f00")); + } + [Test] + public void HashInvalidMSIX() + { // The input is not msix but -m is used - result = TestCommon.RunAICLICommand("hash", TestCommon.GetTestDataFile("AppInstallerTest.cer") + " -m"); + var result = TestCommon.RunAICLICommand("hash", TestCommon.GetTestDataFile("AppInstallerTest.cer") + " -m"); Assert.AreEqual(Constants.ErrorCode.OPC_E_ZIP_MISSING_END_OF_CENTRAL_DIRECTORY, result.ExitCode); Assert.True(result.StdOut.Contains("9b4c49ad7e47afd97d2e666e93347745e1647c55f1a7ebba6d31b7dd5f69ee68")); Assert.True(result.StdOut.Contains("Please verify that the input file is a valid, signed MSIX.")); + } - // Input file not found - result = TestCommon.RunAICLICommand("hash", TestCommon.GetTestDataFile("DoesNot.Exist")); + [Test] + public void HashFileNotFound() + { + var result = TestCommon.RunAICLICommand("hash", TestCommon.GetTestDataFile("DoesNot.Exist")); Assert.AreEqual(Constants.ErrorCode.ERROR_FILE_NOT_FOUND, result.ExitCode); Assert.True(result.StdOut.Contains("File does not exist")); } diff --git a/src/AppInstallerCLIE2ETests/InstallCommand.cs b/src/AppInstallerCLIE2ETests/InstallCommand.cs @@ -8,121 +8,150 @@ namespace AppInstallerCLIE2ETests public class InstallCommand { - // Todo: this should point to a loopback address. Disabling the install tests until we have loopback support done in our e2e tests. // Todo: add unicode test cases after install tests are enabled. - private const string InstallTestSourceUrl = @"https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData"; + private const string InstallTestSourceUrl = @"https://localhost:5001/TestKit"; private const string InstallTestSourceName = @"InstallTestSource"; + private const string DefaultTestSourceUrl = @"https://winget.azureedge.net/cache"; + private const string DefaultTestSourceName = @"winget"; private const string InstallTestExeInstalledFile = @"TestExeInstalled.txt"; - private const string InstallTestMsiInstalledFile = @"AppInstallerTestExeInstaller.exe"; + private const string InstallTestMsiInstalledFile = @"AppInstallerTestMsiInstaller.msi"; private const string InstallTestMsiProductId = @"{A5D36CF1-1993-4F63-BFB4-3ACD910D36A1}"; private const string InstallTestMsixName = @"6c6338fe-41b7-46ca-8ba6-b5ad5312bb0e"; - //[SetUp] + [SetUp] public void Setup() { + TestCommon.RunAICLICommand("source remove", DefaultTestSourceName); Assert.AreEqual(Constants.ErrorCode.S_OK, TestCommon.RunAICLICommand("source add", $"{InstallTestSourceName} {InstallTestSourceUrl}").ExitCode); + } - //[TearDown] + [TearDown] public void TearDown() { TestCommon.RunAICLICommand("source remove", InstallTestSourceName); + TestCommon.RunAICLICommand("source add", $"{DefaultTestSourceName} {DefaultTestSourceUrl}"); TestCommon.WaitForDeploymentFinish(); } - //[Test] - public void InstallCommands() + [Test] + public void AppToInstallDoesNotExist() { - // Cannot find an app to install var result = TestCommon.RunAICLICommand("install", "DoesNotExist"); Assert.AreEqual(Constants.ErrorCode.ERROR_NO_APPLICATIONS_FOUND, result.ExitCode); - Assert.True(result.StdOut.Contains("No app found matching input criteria.")); + Assert.True(result.StdOut.Contains("No package found matching input criteria.")); + } - // Too many apps match the query - result = TestCommon.RunAICLICommand("install", "AppInstallerTest"); + [Test] + public void MultipleAppsMatchQuery() + { + var result = TestCommon.RunAICLICommand("install", "TestExeInstaller"); Assert.AreEqual(Constants.ErrorCode.ERROR_MULTIPLE_APPLICATIONS_FOUND, result.ExitCode); - Assert.True(result.StdOut.Contains("Multiple apps found matching input criteria. Please refine the input.")); + Assert.True(result.StdOut.Contains("Multiple packages found matching input criteria. Please refine the input.")); + } - // Install test exe + [Test] + public void InstallTestExe() + { var installDir = TestCommon.GetRandomTestDir(); - result = TestCommon.RunAICLICommand("install", $"TestExeInstaller --silent -l {installDir}"); + var result = TestCommon.RunAICLICommand("install", $"AppInstallerTest.TestExeInstaller --silent -l {installDir}"); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); Assert.True(result.StdOut.Contains("Successfully installed")); Assert.True(VerifyTestExeInstalled(installDir, "/execustom")); + } - // Install test exe but min os version too high - installDir = TestCommon.GetRandomTestDir(); - result = TestCommon.RunAICLICommand("install", $"InapplicableOsVersion --silent -l {installDir}"); + [Test] + public void InstallTestExeWithInsufficientMinOsVersion() + { + var installDir = TestCommon.GetRandomTestDir(); + var result = TestCommon.RunAICLICommand("install", $"InapplicableOsVersion --silent -l {installDir}"); Assert.AreEqual(Constants.ErrorCode.ERROR_OLD_WIN_VERSION, result.ExitCode); - Assert.True(result.StdOut.Contains("Cannot install application, as it requires a higher version of Windows")); + Assert.True(result.StdOut.Contains("Cannot install package, as it requires a higher version of Windows")); Assert.False(VerifyTestExeInstalled(installDir)); + } - // Install test exe but hash mismatch, passing N should cause the installation to fail - installDir = TestCommon.GetRandomTestDir(); - result = TestCommon.RunAICLICommand("install", $"TestExeSha256Mismatch --silent -l {installDir}", "N"); + [Test] + public void ExeInstallWithHashMismatch() + { + var installDir = TestCommon.GetRandomTestDir(); + var result = TestCommon.RunAICLICommand("install", $"TestExeSha256Mismatch --silent -l {installDir}"); Assert.AreEqual(Constants.ErrorCode.ERROR_INSTALLER_HASH_MISMATCH, result.ExitCode); - Assert.True(result.StdOut.Contains("Installer hash mismatch")); + Assert.True(result.StdOut.Contains("Installer hash does not match")); Assert.False(VerifyTestExeInstalled(installDir)); + } - // Install test exe but hash mismatch, passing Y should cause the installation to continue - installDir = TestCommon.GetRandomTestDir(); - result = TestCommon.RunAICLICommand("install", $"TestExeSha256Mismatch --silent -l {installDir}", "Y"); - Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); - Assert.True(result.StdOut.Contains("Successfully installed")); - Assert.True(VerifyTestExeInstalled(installDir, "/execustom")); - + [Test] + public void InstallWithInno() + { // Install test inno, manifest does not provide silent switch, we should be populating the default - installDir = TestCommon.GetRandomTestDir(); - result = TestCommon.RunAICLICommand("install", $"TestInnoInstaller --silent -l {installDir}"); + var installDir = TestCommon.GetRandomTestDir(); + var result = TestCommon.RunAICLICommand("install", $"TestInnoInstaller --silent -l {installDir}"); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); Assert.True(result.StdOut.Contains("Successfully installed")); Assert.True(VerifyTestExeInstalled(installDir, "/VERYSILENT")); + } + [Test] + public void InstallTestBurn() + { // Install test burn, manifest does not provide silent switch, we should be populating the default - installDir = TestCommon.GetRandomTestDir(); - result = TestCommon.RunAICLICommand("install", $"TestBurnInstaller --silent -l {installDir}"); + var installDir = TestCommon.GetRandomTestDir(); + var result = TestCommon.RunAICLICommand("install", $"TestBurnInstaller --silent -l {installDir}"); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); Assert.True(result.StdOut.Contains("Successfully installed")); Assert.True(VerifyTestExeInstalled(installDir, "/quiet")); + } + [Test] + public void InstallTestNullSoft() + { // Install test Nullsoft, manifest does not provide silent switch, we should be populating the default - installDir = TestCommon.GetRandomTestDir(); - result = TestCommon.RunAICLICommand("install", $"TestNullsoftInstaller --silent -l {installDir}"); + var installDir = TestCommon.GetRandomTestDir(); + var result = TestCommon.RunAICLICommand("install", $"TestNullsoftInstaller --silent -l {installDir}"); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); Assert.True(result.StdOut.Contains("Successfully installed")); Assert.True(VerifyTestExeInstalled(installDir, "/S")); + } - // Install test msi - installDir = TestCommon.GetRandomTestDir(); - result = TestCommon.RunAICLICommand("install", $"TestMsiInstaller --silent -l {installDir}"); + //[Test] + public void InstallTestMSI() + { + var installDir = TestCommon.GetRandomTestDir(); + var result = TestCommon.RunAICLICommand("install", $"TestMsiInstaller --silent -l {installDir}"); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); Assert.True(result.StdOut.Contains("Successfully installed")); Assert.True(VerifyTestMsiInstalledAndCleanup(installDir)); + } + + - // Install test msix - result = TestCommon.RunAICLICommand("install", $"TestMsixInstaller"); + //[Test] + public void InstallTestMSIX() + { + var result = TestCommon.RunAICLICommand("install", $"TestMsixInstaller"); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); Assert.True(result.StdOut.Contains("Successfully installed")); Assert.True(VerifyTestMsixInstalledAndCleanup()); + } - // Install test msix with signature provided - result = TestCommon.RunAICLICommand("install", $"TestMsixWithSignatureHash"); + //[Test] + public void InstallTestMSIXWithSignature() + { + var installDir = TestCommon.GetRandomTestDir(); + var result = TestCommon.RunAICLICommand("install", $"TestMsixWithSignatureHash --silent -l {installDir}"); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); Assert.True(result.StdOut.Contains("Successfully installed")); Assert.True(VerifyTestMsixInstalledAndCleanup()); + } - // Install test msix with signature hash mismatch, passing N should cause the installation to fail - result = TestCommon.RunAICLICommand("install", $"TestMsixSignatureHashMismatch", "N"); + //[Test] + public void InstallTestMSIXWithSignatureHashMismatch() + { + var result = TestCommon.RunAICLICommand("install", $"TestMsixSignatureHashMismatch"); Assert.AreEqual(Constants.ErrorCode.ERROR_INSTALLER_HASH_MISMATCH, result.ExitCode); - Assert.True(result.StdOut.Contains("Installer hash mismatch")); + Assert.True(result.StdOut.Contains("Installer hash does not match")); Assert.False(VerifyTestMsixInstalledAndCleanup()); - - // Install test msix with signature hash mismatch, passing Y should cause the installation to continue - result = TestCommon.RunAICLICommand("install", $"TestMsixSignatureHashMismatch", "Y"); - Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); - Assert.True(result.StdOut.Contains("Successfully installed")); - Assert.True(VerifyTestMsixInstalledAndCleanup()); } private bool VerifyTestExeInstalled(string installDir, string expectedContent = null) diff --git a/src/AppInstallerCLIE2ETests/SearchCommand.cs b/src/AppInstallerCLIE2ETests/SearchCommand.cs @@ -1,65 +1,85 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace AppInstallerCLIE2ETests -{ - using NUnit.Framework; - using System.Threading; - - public class SearchCommand - { - // Todo: use created test source when available - private const string SearchTestSourceUrl = @"https://winget-int.azureedge.net/cache"; - private const string SearchTestSourceName = @"SearchTestSource"; - - [SetUp] - public void Setup() - { - Assert.AreEqual(Constants.ErrorCode.S_OK, TestCommon.RunAICLICommand("source add", $"{SearchTestSourceName} {SearchTestSourceUrl}").ExitCode); - } - - [TearDown] - public void TearDown() - { - TestCommon.RunAICLICommand("source remove", SearchTestSourceName); - - TestCommon.WaitForDeploymentFinish(); - } - - [Test] - public void SearchCommands() - { - // Search without args list every app - var result = TestCommon.RunAICLICommand("search", ""); - Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); - Assert.True(result.StdOut.Contains("Microsoft.PowerToys")); - Assert.True(result.StdOut.Contains("Microsoft.VisualStudioCode")); - - // Search query - result = TestCommon.RunAICLICommand("search", "VisualStudioCode"); - Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); - Assert.True(result.StdOut.Contains("Microsoft.VisualStudioCode")); - - // Search through id found the app - result = TestCommon.RunAICLICommand("search", "--id VisualStudioCode"); - Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); - Assert.True(result.StdOut.Contains("Microsoft.VisualStudioCode")); - - // Search through name. No app found because name is "Visual Studio Code" - result = TestCommon.RunAICLICommand("search", "--name VisualStudioCode"); - Assert.AreEqual(Constants.ErrorCode.ERROR_NO_APPLICATIONS_FOUND, result.ExitCode); - Assert.True(result.StdOut.Contains("No package found matching input criteria.")); - - // Search Microsoft should return multiple - result = TestCommon.RunAICLICommand("search", "Microsoft"); - Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); - Assert.True(result.StdOut.Contains("Microsoft.PowerToys")); - Assert.True(result.StdOut.Contains("Microsoft.VisualStudioCode")); - - // Search Microsoft with exact arg should return none - result = TestCommon.RunAICLICommand("search", "f00-b@r-NOT+REAL -e"); - Assert.AreEqual(Constants.ErrorCode.ERROR_NO_APPLICATIONS_FOUND, result.ExitCode); - Assert.True(result.StdOut.Contains("No package found matching input criteria.")); - } - } +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace AppInstallerCLIE2ETests +{ + using NUnit.Framework; + using System.Threading; + + public class SearchCommand + { + // Todo: use created test source when available + private const string SearchTestSourceUrl = @"https://winget-int.azureedge.net/cache"; + private const string SearchTestSourceName = @"SearchTestSource"; + + [SetUp] + public void Setup() + { + Assert.AreEqual(Constants.ErrorCode.S_OK, TestCommon.RunAICLICommand("source add", $"{SearchTestSourceName} {SearchTestSourceUrl}").ExitCode); + } + + [TearDown] + public void TearDown() + { + TestCommon.RunAICLICommand("source remove", SearchTestSourceName); + + TestCommon.WaitForDeploymentFinish(); + } + + [Test] + public void SearchWithoutArgs() + { + // Search without args list every app + var result = TestCommon.RunAICLICommand("search", ""); + Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); + Assert.True(result.StdOut.Contains("Microsoft.PowerToys")); + Assert.True(result.StdOut.Contains("Microsoft.VisualStudioCode")); + } + + [Test] + public void SearchQuery() + { + // Search query + var result = TestCommon.RunAICLICommand("search", "VisualStudioCode"); + Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); + Assert.True(result.StdOut.Contains("Microsoft.VisualStudioCode")); + } + + [Test] + public void SearchWithID() + { + // Search through id found the app + var result = TestCommon.RunAICLICommand("search", "--id VisualStudioCode"); + Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); + Assert.True(result.StdOut.Contains("Microsoft.VisualStudioCode")); + } + + [Test] + public void SearchWithInvalidName() + { + // Search through name. No app found because name is "Visual Studio Code" + var result = TestCommon.RunAICLICommand("search", "--name VisualStudioCode"); + Assert.AreEqual(Constants.ErrorCode.ERROR_NO_APPLICATIONS_FOUND, result.ExitCode); + Assert.True(result.StdOut.Contains("No package found matching input criteria.")); + } + + [Test] + public void SearchReturnsMultiple() + { + // Search Microsoft should return multiple + var result = TestCommon.RunAICLICommand("search", "Microsoft"); + Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); + Assert.True(result.StdOut.Contains("Microsoft.PowerToys")); + Assert.True(result.StdOut.Contains("Microsoft.VisualStudioCode")); + } + + [Test] + public void SearchWithExactArg() + { + // Search 'powertoys' with exact arg should return none due to case sensitivity + var result = TestCommon.RunAICLICommand("search", "powertoys -e"); + Assert.AreEqual(Constants.ErrorCode.ERROR_NO_APPLICATIONS_FOUND, result.ExitCode); + Assert.True(result.StdOut.Contains("No package found matching input criteria.")); + } + } } \ No newline at end of file diff --git a/src/AppInstallerCLIE2ETests/SetUpFixture.cs b/src/AppInstallerCLIE2ETests/SetUpFixture.cs @@ -12,6 +12,8 @@ namespace AppInstallerCLIE2ETests public class SetUpFixture { private static bool ShouldDisableDevModeOnExit = true; + private static bool ShouldRevertDefaultFileTypeRiskOnExit = true; + private static string DefaultFileTypes = string.Empty; [OneTimeSetUp] public void Setup() @@ -62,6 +64,8 @@ namespace AppInstallerCLIE2ETests ShouldDisableDevModeOnExit = EnableDevMode(true); + ShouldRevertDefaultFileTypeRiskOnExit = DecreaseFileTypeRisk(".exe", false); + Assert.True(TestCommon.RunCommand("certutil.exe", "-addstore -f \"TRUSTEDPEOPLE\" " + TestCommon.GetTestDataFile(Constants.AppInstallerTestCert)), "Add AppInstallerTestCert"); Assert.True(TestCommon.RunCommand("certutil.exe", "-addstore -f \"ROOT\" " + TestCommon.GetTestDataFile(Constants.IndexPackageRootCert)), "Add IndexPackageRootCert"); @@ -76,6 +80,24 @@ namespace AppInstallerCLIE2ETests Assert.True(TestCommon.InstallMsix(TestCommon.AICLIPackagePath), "InstallMsix"); } } + + if (TestContext.Parameters.Exists(Constants.StaticFileRootPathParameter)) + { + TestCommon.StaticFileRootPath = TestContext.Parameters.Get(Constants.StaticFileRootPathParameter); + } + else + { + TestCommon.StaticFileRootPath = Path.GetTempPath(); + } + + if (TestContext.Parameters.Exists(Constants.PackageCertificatePathParameter)) + { + TestCommon.PackageCertificatePath = TestContext.Parameters.Get(Constants.PackageCertificatePathParameter); + } + + ReadTestInstallerPaths(); + + TestIndexSetup.GenerateTestDirectory(); } [OneTimeTearDown] @@ -86,6 +108,11 @@ namespace AppInstallerCLIE2ETests EnableDevMode(false); } + if (ShouldRevertDefaultFileTypeRiskOnExit) + { + DecreaseFileTypeRisk(DefaultFileTypes, true); + } + TestCommon.RunCommand("certutil.exe", $"-delstore \"TRUSTEDPEOPLE\" {Constants.AppInstallerTestCertThumbprint}"); TestCommon.RunCommand("certutil.exe", $"-delstore \"ROOT\" {Constants.IndexPackageRootCertThumbprint}"); @@ -118,8 +145,54 @@ namespace AppInstallerCLIE2ETests return true; } } - return false; } + + private bool DecreaseFileTypeRisk(string fileTypes, bool revert) + { + var defaultFileTypeRiskKey = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Associations"); + string value = (string)defaultFileTypeRiskKey.GetValue("DefaultFileTypeRisk"); + + if (revert) + { + defaultFileTypeRiskKey.SetValue("LowRiskFileTypes", fileTypes); + return false; + } + else + { + if (string.IsNullOrEmpty(value)) + { + DefaultFileTypes = string.Empty; + defaultFileTypeRiskKey.SetValue("LowRiskFileTypes", fileTypes); + } + else + { + DefaultFileTypes = value; + defaultFileTypeRiskKey.SetValue("LowRiskFileTypes", string.Concat(value, fileTypes)); + } + return true; + } + } + + private void ReadTestInstallerPaths() + { + if (TestContext.Parameters.Exists(Constants.ExeInstallerPathParameter) + && File.Exists(TestContext.Parameters.Get(Constants.ExeInstallerPathParameter))) + { + TestCommon.ExeInstallerPath = TestContext.Parameters.Get(Constants.ExeInstallerPathParameter); + } + + if (TestContext.Parameters.Exists(Constants.MsiInstallerPathParameter) + && File.Exists(TestContext.Parameters.Get(Constants.MsiInstallerPathParameter))) + { + TestCommon.MsiInstallerPath = TestContext.Parameters.Get(Constants.MsiInstallerPathParameter); + } + + if (TestContext.Parameters.Exists(Constants.MsixInstallerPathParameter) + && File.Exists(TestContext.Parameters.Get(Constants.MsixInstallerPathParameter))) + { + TestCommon.MsixInstallerPath = TestContext.Parameters.Get(Constants.MsixInstallerPathParameter); + } + } } } diff --git a/src/AppInstallerCLIE2ETests/ShowCommand.cs b/src/AppInstallerCLIE2ETests/ShowCommand.cs @@ -27,7 +27,7 @@ namespace AppInstallerCLIE2ETests } [Test] - public void ShowCommands() + public void ShowWithNoArgs() { // Show with no arg lists every app and a warning message var result = TestCommon.RunAICLICommand("show", $"-s {ShowTestSourceName}"); @@ -35,25 +35,41 @@ namespace AppInstallerCLIE2ETests Assert.True(result.StdOut.Contains("Multiple packages found matching input criteria. Please refine the input.")); Assert.True(result.StdOut.Contains("Microsoft.PowerToys")); Assert.True(result.StdOut.Contains("Microsoft.VisualStudioCode")); + } + [Test] + public void ShowWithNoMatches() + { // Show with 0 search match shows a "please refine input" - result = TestCommon.RunAICLICommand("show", $"DoesNotExist -s {ShowTestSourceName}"); + var result = TestCommon.RunAICLICommand("show", $"DoesNotExist -s {ShowTestSourceName}"); Assert.AreEqual(Constants.ErrorCode.ERROR_NO_APPLICATIONS_FOUND, result.ExitCode); Assert.True(result.StdOut.Contains("No package found matching input criteria.")); + } + [Test] + public void ShowWithSubstringMatch() + { // Show with a substring match still returns 0 results - result = TestCommon.RunAICLICommand("show", $"Microsoft -s {ShowTestSourceName}"); + var result = TestCommon.RunAICLICommand("show", $"Microsoft -s {ShowTestSourceName}"); Assert.AreEqual(Constants.ErrorCode.ERROR_NO_APPLICATIONS_FOUND, result.ExitCode); Assert.True(result.StdOut.Contains("No package found matching input criteria.")); + } + [Test] + public void ShowWithSingleMatch() + { // Show with 1 search match shows detailed manifest info - result = TestCommon.RunAICLICommand("show", $"Microsoft.VisualStudioCode -s {ShowTestSourceName}"); + var result = TestCommon.RunAICLICommand("show", $"Microsoft.VisualStudioCode -s {ShowTestSourceName}"); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); Assert.True(result.StdOut.Contains("Microsoft.VisualStudioCode")); Assert.True(result.StdOut.Contains("Visual Studio Code")); + } + [Test] + public void ShowWithVersions() + { // Show with --versions list the versions - result = TestCommon.RunAICLICommand("show", $"Microsoft.VisualStudioCode --versions -s {ShowTestSourceName}"); + var result = TestCommon.RunAICLICommand("show", $"Microsoft.VisualStudioCode --versions -s {ShowTestSourceName}"); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); Assert.True(result.StdOut.Contains("Microsoft.VisualStudioCode")); Assert.True(result.StdOut.Contains("1.41.1")); diff --git a/src/AppInstallerCLIE2ETests/SourceCommand.cs b/src/AppInstallerCLIE2ETests/SourceCommand.cs @@ -11,72 +11,112 @@ namespace AppInstallerCLIE2ETests private const string SourceTestSourceUrl = @"https://winget-int.azureedge.net/cache"; private const string SourceTestSourceName = @"SourceTestSource"; + [SetUp] + public void Setup() + { + Assert.AreEqual(Constants.ErrorCode.S_OK, TestCommon.RunAICLICommand("source add", $"{SourceTestSourceName} {SourceTestSourceUrl}").ExitCode); + } + [TearDown] public void TearDown() { TestCommon.RunAICLICommand("source remove", SourceTestSourceName); - TestCommon.WaitForDeploymentFinish(); } [Test] - public void SourceCommands() + public void AddSource() { - // Add test source should succeed - var result = TestCommon.RunAICLICommand("source add", $"{SourceTestSourceName} {SourceTestSourceUrl}"); + var result = TestCommon.RunAICLICommand("source add", $"SourceTest {SourceTestSourceUrl}"); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); Assert.True(result.StdOut.Contains("Done")); + TestCommon.RunAICLICommand("source remove", $"-n SourceTest"); + } + [Test] + public void AddSourceWithDuplicateName() + { // Add source with duplicate name should fail - result = TestCommon.RunAICLICommand("source add", $"{SourceTestSourceName} https://microsoft.com"); + var result = TestCommon.RunAICLICommand("source add", $"{SourceTestSourceName} https://microsoft.com"); Assert.AreEqual(Constants.ErrorCode.ERROR_SOURCE_NAME_ALREADY_EXISTS, result.ExitCode); Assert.True(result.StdOut.Contains("A source with the given name already exists and refers to a different location")); + } + [Test] + public void AddSourceWithInvalidURL() + { // Add source with invalid url should fail - result = TestCommon.RunAICLICommand("source add", "AnotherSource https://microsoft.com"); + var result = TestCommon.RunAICLICommand("source add", "AnotherSource https://microsoft.com"); Assert.AreEqual(Constants.ErrorCode.ERROR_NO_RANGES_PROCESSED, result.ExitCode); - Assert.True(result.StdOut.Contains("error occurred while executing the command")); + Assert.True(result.StdOut.Contains("An unexpected error occurred while executing the command")); + } + + [Test] + public void AddSourceWithHttpURL() + { // Add source with an HTTP url should fail - result = TestCommon.RunAICLICommand("source add", "Insecure http://microsoft.com"); + var result = TestCommon.RunAICLICommand("source add", "Insecure http://microsoft.com"); Assert.AreEqual(Constants.ErrorCode.ERROR_SOURCE_NOT_SECURE, result.ExitCode); Assert.True(result.StdOut.Contains("error occurred while executing the command")); + } + [Test] + public void ListWithNoArgs() + { // List with no args should list all available sources - result = TestCommon.RunAICLICommand("source list", ""); + var result = TestCommon.RunAICLICommand("source list", ""); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); Assert.True(result.StdOut.Contains("https://winget-int.azureedge.net/cache")); + } - // List when source name matches, it shows detailed info - result = TestCommon.RunAICLICommand("source list", $"-n {SourceTestSourceName}"); + [Test] + public void ListWithSourceName() + { + var result = TestCommon.RunAICLICommand("source list", $"-n {SourceTestSourceName}"); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); Assert.True(result.StdOut.Contains("SourceTestSource")); Assert.True(result.StdOut.Contains("https://winget-int.azureedge.net/cache")); - Assert.True(result.StdOut.Contains("Microsoft.Winget.Source.int")); + Assert.True(result.StdOut.Contains("Microsoft.Winget.Source")); Assert.True(result.StdOut.Contains("Updated")); + } - // List when source name does not match - result = TestCommon.RunAICLICommand("source list", "-n UnknownName"); + [Test] + public void ListSourceNameMismatch() + { + var result = TestCommon.RunAICLICommand("source list", "-n UnknownName"); Assert.AreEqual(Constants.ErrorCode.ERROR_SOURCE_NAME_DOES_NOT_EXIST, result.ExitCode); Assert.True(result.StdOut.Contains("Did not find a source named")); + } - // Update should succeed - result = TestCommon.RunAICLICommand("source update", $"-n {SourceTestSourceName}"); + [Test] + public void SourceUpdate() + { + var result = TestCommon.RunAICLICommand("source update", $"-n {SourceTestSourceName}"); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); Assert.True(result.StdOut.Contains("Done")); + } - // Update with bad name should fail - result = TestCommon.RunAICLICommand("source update", "-n UnknownName"); + [Test] + public void SourceUpdateWithInvalidName() + { + var result = TestCommon.RunAICLICommand("source update", "-n UnknownName"); Assert.AreEqual(Constants.ErrorCode.ERROR_SOURCE_NAME_DOES_NOT_EXIST, result.ExitCode); Assert.True(result.StdOut.Contains("Did not find a source named: UnknownName")); + } - // Remove with a bad name should fail - result = TestCommon.RunAICLICommand("source remove", "-n UnknownName"); + [Test] + public void SourceRemoveInvalidName() + { + var result = TestCommon.RunAICLICommand("source remove", "-n UnknownName"); Assert.AreEqual(Constants.ErrorCode.ERROR_SOURCE_NAME_DOES_NOT_EXIST, result.ExitCode); Assert.True(result.StdOut.Contains("Did not find a source named: UnknownName")); + } - // Remove with a good name should succeed - result = TestCommon.RunAICLICommand("source remove", $"-n {SourceTestSourceName}"); + [Test] + public void SourceRemoveValidName() + { + var result = TestCommon.RunAICLICommand("source remove", $"-n {SourceTestSourceName}"); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); Assert.True(result.StdOut.Contains("Done")); } diff --git a/src/AppInstallerCLIE2ETests/Test.runsettings b/src/AppInstallerCLIE2ETests/Test.runsettings @@ -14,13 +14,21 @@ LooseFileRegistration: Bool to set if loose file registration should be used. InvokeCommandInDesktopPackage: Bool to indicate using Invoke-CommandInDesktopPackage for test execution. This is used when AppExecutionAlias is not available, or disabled. + StaticFileRootPath: Path to the set of static test files that will be served as the source for testing purposes. + MsixTestInstallerPath : The MSIX (or APPX) Installer executable under test. + ExeTestInstallerPath: The Exe Installer executable under test. + PackageCertificatePath: Signing Certificate Path used to certify Index Source Package --> <TestRunParameters> - <Parameter name="PackagedContext" value="true" /> - <Parameter name="VerboseLogging" value="false" /> - <Parameter name="AICLIPath" value="AppInst.exe" /> - <Parameter name="AICLIPackagePath" value="AppInstallerCLIPackage.appxbundle" /> - <Parameter name="LooseFileRegistration" value="false" /> - <Parameter name="InvokeCommandInDesktopPackage" value="false" /> + <Parameter name="PackagedContext" value="true" /> + <Parameter name="VerboseLogging" value="false" /> + <Parameter name="AICLIPath" value="AppInst.exe" /> + <Parameter name="AICLIPackagePath" value="AppInstallerCLIPackage.appxbundle" /> + <Parameter name="LooseFileRegistration" value="false" /> + <Parameter name="InvokeCommandInDesktopPackage" value="false" /> + <Parameter name="StaticFileRootPath" value="\TestLocalIndex" /> + <Parameter name="MsixTestInstallerPath" value="MsixTestInstaller.msix" /> + <Parameter name="ExeTestInstallerPath" value="ExeTestInstaller.exe" /> + <Parameter name="PackageCertificatePath" value="certificate.pfx"/> </TestRunParameters> </RunSettings> \ No newline at end of file diff --git a/src/AppInstallerCLIE2ETests/TestCommon.cs b/src/AppInstallerCLIE2ETests/TestCommon.cs @@ -23,6 +23,16 @@ namespace AppInstallerCLIE2ETests public static bool InvokeCommandInDesktopPackage { get; set; } + public static string StaticFileRootPath { get; set; } + + public static string ExeInstallerPath { get; set; } + + public static string MsiInstallerPath { get; set; } + + public static string MsixInstallerPath { get; set; } + + public static string PackageCertificatePath { get; set; } + public struct RunCommandResult { public int ExitCode; diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestBurnInstaller.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestBurnInstaller.yaml @@ -1,13 +1,14 @@ -Id: AppInstallerTest.TestBurnInstaller -Name: TestBurnInstaller -Version: 1.0.0.0 -Publisher: AppInstallerTest -License: Test -Installers: - - Arch: x86 - Url: https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestExeInstaller.exe - Sha256: 7c616e2fe3853b555ddea4cb50bd307da1dc47898a5fbc3a8646a470107802ab - InstallerType: burn - Switches: - InstallLocation: /InstallDir <INSTALLPATH> -ManifestVersion: 0.1.0 +Id: AppInstallerTest.TestBurnInstaller +Name: TestBurnInstaller +Version: 1.0.0.0 +Publisher: AppInstallerTest +License: Test +Installers: + - Arch: x86 + Url: https://localhost:5001/TestKit/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe + + Sha256: <EXEHASH> + InstallerType: burn + Switches: + InstallLocation: /InstallDir <INSTALLPATH> +ManifestVersion: 0.1.0 diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller.yaml @@ -1,19 +1,19 @@ -Id: AppInstallerTest.TestExeInstaller -Name: TestExeInstaller -Version: 1.0.0.0 -Publisher: AppInstallerTest -License: Test -Installers: - - Arch: x86 - Url: https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestExeInstaller.exe - Sha256: 7c616e2fe3853b555ddea4cb50bd307da1dc47898a5fbc3a8646a470107802ab - InstallerType: exe - Switches: - Custom: /execustom - SilentWithProgress: /exeswp - Silent: /exesilent - Interactive: /exeinteractive - Language: /exeenus - Log: /exelog <LOGPATH> - InstallLocation: /InstallDir <INSTALLPATH> -ManifestVersion: 0.1.0 +Id: AppInstallerTest.TestExeInstaller +Name: TestExeInstaller +Version: 1.0.0.0 +Publisher: AppInstallerTest +License: Test +Installers: + - Arch: x86 + Url: https://localhost:5001/TestKit/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe + Sha256: <EXEHASH> + InstallerType: exe + Switches: + Custom: /execustom + SilentWithProgress: /exeswp + Silent: /exesilent + Interactive: /exeinteractive + Language: /exeenus + Log: /exelog <LOGPATH> + InstallLocation: /InstallDir <INSTALLPATH> +ManifestVersion: 0.1.0 diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller_InapplicableOsVersion.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller_InapplicableOsVersion.yaml @@ -1,20 +1,20 @@ -Id: AppInstallerTest.InapplicableOsVersion -Name: InapplicableOsVersion -Version: 1.0.0.0 -Publisher: AppInstallerTest -MinOSVersion: 11.0.0.0 -License: Test -Installers: - - Arch: x86 - Url: https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestExeInstaller.exe - Sha256: 7c616e2fe3853b555ddea4cb50bd307da1dc47898a5fbc3a8646a470107802ab - InstallerType: exe - Switches: - Custom: /execustom - SilentWithProgress: /exeswp - Silent: /exesilent - Interactive: /exeinteractive - Language: /exeenus - Log: /exelog <LOGPATH> - InstallLocation: /InstallDir <INSTALLPATH> -ManifestVersion: 0.1.0 +Id: AppInstallerTest.InapplicableOsVersion +Name: InapplicableOsVersion +Version: 1.0.0.0 +Publisher: AppInstallerTest +MinOSVersion: 11.0.0.0 +License: Test +Installers: + - Arch: x86 + Url: https://localhost:5001/TestKit/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe + Sha256: <EXEHASH> + InstallerType: exe + Switches: + Custom: /execustom + SilentWithProgress: /exeswp + Silent: /exesilent + Interactive: /exeinteractive + Language: /exeenus + Log: /exelog <LOGPATH> + InstallLocation: /InstallDir <INSTALLPATH> +ManifestVersion: 0.1.0 diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller_Sha256Mismatch.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller_Sha256Mismatch.yaml @@ -1,19 +1,19 @@ -Id: AppInstallerTest.TestExeSha256Mismatch -Name: TestExeSha256Mismatch -Version: 1.0.0.0 -Publisher: AppInstallerTest -License: Test -Installers: - - Arch: x86 - Url: https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestExeInstaller.exe - Sha256: 7c616e2fe3853b555ddea4cb50bd307da1dc47898a5fbc3a8646a470107802aa - InstallerType: exe - Switches: - Custom: /execustom - SilentWithProgress: /exeswp - Silent: /exesilent - Interactive: /exeinteractive - Language: /exeenus - Log: /exelog <LOGPATH> - InstallLocation: /InstallDir <INSTALLPATH> -ManifestVersion: 0.1.0 +Id: AppInstallerTest.TestExeSha256Mismatch +Name: TestExeSha256Mismatch +Version: 1.0.0.0 +Publisher: AppInstallerTest +License: Test +Installers: + - Arch: x86 + Url: https://localhost:5001/TestKit/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe + Sha256: 0000000000000000000000000000000000000000000000000000000000000000 + InstallerType: exe + Switches: + Custom: /execustom + SilentWithProgress: /exeswp + Silent: /exesilent + Interactive: /exeinteractive + Language: /exeenus + Log: /exelog <LOGPATH> + InstallLocation: /InstallDir <INSTALLPATH> +ManifestVersion: 0.1.0 diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestInnoInstaller.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestInnoInstaller.yaml @@ -1,13 +1,13 @@ -Id: AppInstallerTest.TestInnoInstaller -Name: TestInnoInstaller -Version: 1.0.0.0 -Publisher: AppInstallerTest -License: Test -Installers: - - Arch: x86 - Url: https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestExeInstaller.exe - Sha256: 7c616e2fe3853b555ddea4cb50bd307da1dc47898a5fbc3a8646a470107802ab - InstallerType: inno - Switches: - InstallLocation: /InstallDir <INSTALLPATH> -ManifestVersion: 0.1.0 +Id: AppInstallerTest.TestInnoInstaller +Name: TestInnoInstaller +Version: 1.0.0.0 +Publisher: AppInstallerTest +License: Test +Installers: + - Arch: x86 + Url: https://localhost:5001/TestKit/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe + Sha256: <EXEHASH> + InstallerType: inno + Switches: + InstallLocation: /InstallDir <INSTALLPATH> +ManifestVersion: 0.1.0 diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestInvalidManifest.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestInvalidManifest.yaml @@ -1,19 +1,19 @@ -Id: TestInvalidManifest TestInvalidManifest -Name: TestInvalidManifest -Version: 1.0.0.0 -Publisher: AppInstallerTest -License: Test -Installers: - - Arch: x86 - Url: https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestExeInstaller.exe - Sha256: 7c616e2fe3853b555ddea4cb50bd307da1dc47898a5fbc3a8646a470107802ab - InstallerType: exe - Switches: - Custom: /execustom - SilentWithProgress: /exeswp - Silent: /exesilent - Interactive: /exeinteractive - Language: /exeenus - Log: /exelog <LOGPATH> - InstallLocation: /InstallDir <INSTALLPATH> -ManifestVersion: 0.1.0 +Id: TestInvalidManifest TestInvalidManifest +Name: TestInvalidManifest +Version: 1.0.0.0 +Publisher: AppInstallerTest +License: Test +Installers: + - Arch: x86 + Url: https://localhost:5001/TestKit/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe + Sha256: <EXEHASH> + InstallerType: exe + Switches: + Custom: /execustom + SilentWithProgress: /exeswp + Silent: /exesilent + Interactive: /exeinteractive + Language: /exeenus + Log: /exelog <LOGPATH> + InstallLocation: /InstallDir <INSTALLPATH> +ManifestVersion: 0.1.0 diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsiInstaller.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsiInstaller.yaml @@ -1,11 +1,11 @@ -Id: AppInstallerTest.TestMsiInstaller -Name: TestMsiInstaller -Version: 1.0.0.0 -Publisher: AppInstallerTest -License: Test -Installers: - - Arch: x86 - Url: https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestMsiInstaller.msi - Sha256: 18a07fadd84fd66fce094e323a51afba648fd8c2a826573d61b60960d7e35e63 - InstallerType: msi -ManifestVersion: 0.1.0 +Id: AppInstallerTest.TestMsiInstaller +Name: TestMsiInstaller +Version: 1.0.0.0 +Publisher: AppInstallerTest +License: Test +Installers: + - Arch: x86 + Url: https://localhost:5001/TestKit/AppInstallerTestMsiInstaller/AppInstallerTestMsiInstaller.msi + Sha256: <MSIHASH> + InstallerType: msi +ManifestVersion: 0.1.0 diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsixInstaller.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsixInstaller.yaml @@ -1,11 +1,11 @@ -Id: AppInstallerTest.TestMsixInstaller -Name: TestMsixInstaller -Version: 1.0.0.0 -Publisher: AppInstallerTest -License: Test -Installers: - - Arch: x86 - Url: https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestMsixInstaller.msix - Sha256: 714c861a52478bfa44228739c500c9429f4e75c7b78d48cac06bfb8f62bad627 - InstallerType: msix -ManifestVersion: 0.1.0 +Id: AppInstallerTest.TestMsixInstaller +Name: TestMsixInstaller +Version: 1.0.0.0 +Publisher: AppInstallerTest +License: Test +Installers: + - Arch: x86 + Url: https://localhost:5001/TestKit/AppInstallerTestMsixInstaller/AppInstallerTestMsixInstaller.msix + Sha256: <MSIXHASH> + InstallerType: msix +ManifestVersion: 0.1.0 diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsixInstaller_SignatureHashMismatch.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsixInstaller_SignatureHashMismatch.yaml @@ -1,12 +1,12 @@ -Id: AppInstallerTest.TestMsixSignatureHashMismatch -Name: TestMsixSignatureHashMismatch -Version: 1.0.0.0 -Publisher: AppInstallerTest -License: Test -Installers: - - Arch: x86 - Url: https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestMsixInstaller.msix - Sha256: 714c861a52478bfa44228739c500c9429f4e75c7b78d48cac06bfb8f62bad626 - SignatureSha256: d8a54b79a9c5956df5b338fdaf37f48e56316465defd182cbe64d8e5d3d53d4d - InstallerType: msix -ManifestVersion: 0.1.0 +Id: AppInstallerTest.TestMsixSignatureHashMismatch +Name: TestMsixSignatureHashMismatch +Version: 1.0.0.0 +Publisher: AppInstallerTest +License: Test +Installers: + - Arch: x86 + Url: https://localhost:5001/TestKit/AppInstallerTestMsixInstaller/AppInstallerTestMsixInstaller.msix + Sha256: <MSIXHASH> + SignatureSha256: 0000000000000000000000000000000000000000000000000000000000000000 + InstallerType: msix +ManifestVersion: 0.1.0 diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsixInstaller_WithSignatureHash.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsixInstaller_WithSignatureHash.yaml @@ -1,12 +1,12 @@ -Id: AppInstallerTest.TestMsixWithSignatureHash -Name: TestMsixWithSignatureHash -Version: 1.0.0.0 -Publisher: AppInstallerTest -License: Test -Installers: - - Arch: x86 - Url: https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestMsixInstaller.msix - Sha256: 714c861a52478bfa44228739c500c9429f4e75c7b78d48cac06bfb8f62bad627 - SignatureSha256: d8a54b79a9c5956df5b338fdaf37f48e56316465defd182cbe64d8e5d3d53d4e - InstallerType: msix -ManifestVersion: 0.1.0 +Id: AppInstallerTest.TestMsixWithSignatureHash +Name: TestMsixWithSignatureHash +Version: 1.0.0.0 +Publisher: AppInstallerTest +License: Test +Installers: + - Arch: x86 + Url: https://localhost:5001/TestKit/AppInstallerTestMsixInstaller/AppInstallerTestMsixInstaller.msix + Sha256: <MSIXHASH> + SignatureSha256: <SIGNATUREHASH> + InstallerType: msix +ManifestVersion: 0.1.0 diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestNullsoftInstaller.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestNullsoftInstaller.yaml @@ -1,13 +1,13 @@ -Id: AppInstallerTest.TestNullsoftInstaller -Name: TestNullsoftInstaller -Version: 1.0.0.0 -Publisher: AppInstallerTest -License: Test -Installers: - - Arch: x86 - Url: https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestExeInstaller.exe - Sha256: 7c616e2fe3853b555ddea4cb50bd307da1dc47898a5fbc3a8646a470107802ab - InstallerType: nullsoft - Switches: - InstallLocation: /InstallDir <INSTALLPATH> -ManifestVersion: 0.1.0 +Id: AppInstallerTest.TestNullsoftInstaller +Name: TestNullsoftInstaller +Version: 1.0.0.0 +Publisher: AppInstallerTest +License: Test +Installers: + - Arch: x86 + Url: https://localhost:5001/TestKit/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe + Sha256: <EXEHASH> + InstallerType: nullsoft + Switches: + InstallLocation: /InstallDir <INSTALLPATH> +ManifestVersion: 0.1.0 diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestValidManifest.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestValidManifest.yaml @@ -0,0 +1,19 @@ +Id: AppInstallerTest.TestValidManifest +Name: TestValidManifest +Version: 1.0.0.0 +Publisher: AppInstallerTest +License: Test +Installers: + - Arch: x86 + Url: https://localhost:5001/TestKit/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe + Sha256: 0000000000000000000000000000000000000000000000000000000000000000 + InstallerType: exe + Switches: + Custom: /execustom + SilentWithProgress: /exeswp + Silent: /exesilent + Interactive: /exeinteractive + Language: /exeenus + Log: /exelog <LOGPATH> + InstallLocation: /InstallDir <INSTALLPATH> +ManifestVersion: 0.1.0 diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestWarningManifest.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestWarningManifest.yaml @@ -1,12 +1,12 @@ -Id: TestWarning.Manifest -Name: TestWarningManifest -Version: 1.0.0.0 -Publisher: AppInstallerTest -License: Test -Installers: - - Arch: x86 - Url: https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestExeInstaller.exe - Sha256: 7c616e2fe3853b555ddea4cb50bd307da1dc47898a5fbc3a8646a470107802ab - InstallerType: exe - Switches: -ManifestVersion: 0.1.0 +Id: TestWarning.Manifest +Name: TestWarningManifest +Version: 1.0.0.0 +Publisher: AppInstallerTest +License: Test +Installers: + - Arch: x86 + Url: https://localhost:5001/TestKit/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe + Sha256: <EXEHASH> + InstallerType: exe + Switches: +ManifestVersion: 0.1.0 diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TëstExeInstaller.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TëstExeInstaller.yaml @@ -1,19 +1,19 @@ -Id: AppInstallerTest.TëstExeInstaller -Name: TestExeInstaller -Version: 1.0.0.0 -Publisher: AppInstallerTest -License: Test -Installers: - - Arch: x86 - Url: https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestExeInstaller.exe - Sha256: 7c616e2fe3853b555ddea4cb50bd307da1dc47898a5fbc3a8646a470107802ab - InstallerType: exe - Switches: - Custom: /execustom - SilentWithProgress: /exeswp - Silent: /exesilent - Interactive: /exeinteractive - Language: /exeenus - Log: /exelog <LOGPATH> - InstallLocation: /InstallDir <INSTALLPATH> -ManifestVersion: 0.1.0 +Id: AppInstallerTest.TëstExeInstaller +Name: TestExeInstaller +Version: 1.0.0.0 +Publisher: AppInstallerTest +License: Test +Installers: + - Arch: x86 + Url: https://localhost:5001/TestKit/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe + Sha256: 0000000000000000000000000000000000000000000000000000000000000000 + InstallerType: exe + Switches: + Custom: /execustom + SilentWithProgress: /exeswp + Silent: /exesilent + Interactive: /exeinteractive + Language: /exeenus + Log: /exelog <LOGPATH> + InstallLocation: /InstallDir <INSTALLPATH> +ManifestVersion: 0.1.0 diff --git a/src/AppInstallerCLIE2ETests/TestData/Package/AppxManifest.xml b/src/AppInstallerCLIE2ETests/TestData/Package/AppxManifest.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8"?> +<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" + xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" + xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" + IgnorableNamespaces="uap uap3"> + + <Identity Name="WingetE2E.Tests" + ProcessorArchitecture="neutral" + Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" + Version="2020.805.713.335" /> + + <!-- Commit in which this package was based on 0563b4dd28f58985a8e60762ede9824f1b7ea310--> + + <Properties> + <DisplayName>WinGet Source</DisplayName> + <PublisherDisplayName>Microsoft Corporation</PublisherDisplayName> + <Logo>Assets\AppPackageStoreLogo.png</Logo> + </Properties> + + <Dependencies> + <TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.16299.0" MaxVersionTested="10.0.18287.0" /> + </Dependencies> + + <Applications> + <Application Id="SourceData"> + <uap:VisualElements DisplayName="WinGet Source" + Square150x150Logo="Assets\AppPackageStoreLogo.scale-150.png" + Square44x44Logo="Assets\AppPackageStoreLogo.scale-100.png" + Description="WinGet Source" + BackgroundColor="#0078d7" + AppListEntry="none" /> + <Extensions> + <uap3:Extension Category="windows.appExtension"> + <uap3:AppExtension Name="com.microsoft.winget.source" + Id="IndexDB" + DisplayName="WinGet Source" + Description="WinGet Source" + PublicFolder="Public"> + </uap3:AppExtension> + </uap3:Extension> + </Extensions> + </Application> + </Applications> + + <Resources> + <Resource Language="und" /> + </Resources> + +</Package> diff --git a/src/AppInstallerCLIE2ETests/TestData/Package/Assets/AppPackageStoreLogo.png.png b/src/AppInstallerCLIE2ETests/TestData/Package/Assets/AppPackageStoreLogo.png.png Binary files differ. diff --git a/src/AppInstallerCLIE2ETests/TestData/Package/Assets/AppPackageStoreLogo.scale-100.png b/src/AppInstallerCLIE2ETests/TestData/Package/Assets/AppPackageStoreLogo.scale-100.png Binary files differ. diff --git a/src/AppInstallerCLIE2ETests/TestData/Package/Assets/AppPackageStoreLogo.scale-125.png b/src/AppInstallerCLIE2ETests/TestData/Package/Assets/AppPackageStoreLogo.scale-125.png Binary files differ. diff --git a/src/AppInstallerCLIE2ETests/TestData/Package/Assets/AppPackageStoreLogo.scale-150.png b/src/AppInstallerCLIE2ETests/TestData/Package/Assets/AppPackageStoreLogo.scale-150.png Binary files differ. diff --git a/src/AppInstallerCLIE2ETests/TestData/Package/Assets/AppPackageStoreLogo.scale-200.png b/src/AppInstallerCLIE2ETests/TestData/Package/Assets/AppPackageStoreLogo.scale-200.png Binary files differ. diff --git a/src/AppInstallerCLIE2ETests/TestData/Package/Assets/AppPackageStoreLogo.scale-400.png b/src/AppInstallerCLIE2ETests/TestData/Package/Assets/AppPackageStoreLogo.scale-400.png Binary files differ. diff --git a/src/AppInstallerCLIE2ETests/TestData/Package/Assets/contrast-black/AppPackageStoreLogo.scale-100_contrast-black.png b/src/AppInstallerCLIE2ETests/TestData/Package/Assets/contrast-black/AppPackageStoreLogo.scale-100_contrast-black.png Binary files differ. diff --git a/src/AppInstallerCLIE2ETests/TestData/Package/Assets/contrast-black/AppPackageStoreLogo.scale-125_contrast-black.png b/src/AppInstallerCLIE2ETests/TestData/Package/Assets/contrast-black/AppPackageStoreLogo.scale-125_contrast-black.png Binary files differ. diff --git a/src/AppInstallerCLIE2ETests/TestData/Package/Assets/contrast-black/AppPackageStoreLogo.scale-150_contrast-black.png b/src/AppInstallerCLIE2ETests/TestData/Package/Assets/contrast-black/AppPackageStoreLogo.scale-150_contrast-black.png Binary files differ. diff --git a/src/AppInstallerCLIE2ETests/TestData/Package/Assets/contrast-black/AppPackageStoreLogo.scale-200_contrast-black.png b/src/AppInstallerCLIE2ETests/TestData/Package/Assets/contrast-black/AppPackageStoreLogo.scale-200_contrast-black.png Binary files differ. diff --git a/src/AppInstallerCLIE2ETests/TestData/Package/Assets/contrast-black/AppPackageStoreLogo.scale-400_contrast-black.png b/src/AppInstallerCLIE2ETests/TestData/Package/Assets/contrast-black/AppPackageStoreLogo.scale-400_contrast-black.png Binary files differ. diff --git a/src/AppInstallerCLIE2ETests/TestData/Package/Assets/contrast-white/AppPackageStoreLogo.scale-100_contrast-white.png b/src/AppInstallerCLIE2ETests/TestData/Package/Assets/contrast-white/AppPackageStoreLogo.scale-100_contrast-white.png Binary files differ. diff --git a/src/AppInstallerCLIE2ETests/TestData/Package/Assets/contrast-white/AppPackageStoreLogo.scale-125_contrast-white.png b/src/AppInstallerCLIE2ETests/TestData/Package/Assets/contrast-white/AppPackageStoreLogo.scale-125_contrast-white.png Binary files differ. diff --git a/src/AppInstallerCLIE2ETests/TestData/Package/Assets/contrast-white/AppPackageStoreLogo.scale-150_contrast-white.png b/src/AppInstallerCLIE2ETests/TestData/Package/Assets/contrast-white/AppPackageStoreLogo.scale-150_contrast-white.png Binary files differ. diff --git a/src/AppInstallerCLIE2ETests/TestData/Package/Assets/contrast-white/AppPackageStoreLogo.scale-200_contrast-white.png b/src/AppInstallerCLIE2ETests/TestData/Package/Assets/contrast-white/AppPackageStoreLogo.scale-200_contrast-white.png Binary files differ. diff --git a/src/AppInstallerCLIE2ETests/TestData/Package/Assets/contrast-white/AppPackageStoreLogo.scale-400_contrast-white.png b/src/AppInstallerCLIE2ETests/TestData/Package/Assets/contrast-white/AppPackageStoreLogo.scale-400_contrast-white.png Binary files differ. diff --git a/src/AppInstallerCLIE2ETests/TestHashHelper.cs b/src/AppInstallerCLIE2ETests/TestHashHelper.cs @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +using System; +using System.IO; +using System.Security.Cryptography; +using Microsoft.Msix.Utils.ProcessRunner; + +namespace AppInstallerCLIE2ETests +{ + public class TestHashHelper + { + public static string ExeInstallerHashValue { get; set; } + + public static string MsiInstallerHashValue { get; set; } + + public static string MsixInstallerHashValue { get; set; } + + public static string SignatureHashValue { get; set; } + + public static void HashInstallers() + { + if (!string.IsNullOrEmpty(TestCommon.ExeInstallerPath)) + { + ExeInstallerHashValue = HashFile(TestCommon.ExeInstallerPath); + } + + if (!string.IsNullOrEmpty(TestCommon.MsiInstallerPath)) + { + MsiInstallerHashValue = HashFile(TestCommon.MsiInstallerPath); + } + + if (!string.IsNullOrEmpty(TestCommon.MsixInstallerPath)) + { + MsixInstallerHashValue = HashFile(TestCommon.MsixInstallerPath); + SignatureHashValue = HashSignatureFromMSIX(TestCommon.MsixInstallerPath); + } + } + + /// <summary> + /// Iterates through all manifest files in a directory and replaces the hash <token> with the + /// corresponding installer hash token. + /// </summary> + /// <param name="pathToManifestDir"></param> + public static void ReplaceManifestHashToken(string pathToManifestDir) + { + var dir = new DirectoryInfo(pathToManifestDir); + FileInfo[] files = dir.GetFiles(); + + foreach (FileInfo file in files) + { + string text = File.ReadAllText(file.FullName); + + if (text.Contains("<EXEHASH>")) + { + text = text.Replace("<EXEHASH>", ExeInstallerHashValue); + File.WriteAllText(file.FullName, text); + } + else if (text.Contains("<MSIHASH>")) + { + text = text.Replace("<MSIHASH>", MsiInstallerHashValue); + File.WriteAllText(file.FullName, text); + } + else if (text.Contains("<MSIXHASH>")) + { + text = text.Replace("<MSIXHASH>", MsixInstallerHashValue); + + if (text.Contains("<SIGNATUREHASH>")) + { + text = text.Replace("<SIGNATUREHASH>", SignatureHashValue); + } + + File.WriteAllText(file.FullName, text); + } + } + } + + public static string HashSignatureFromMSIX(string packageFilePath) + { + // Obtain MakeAppX Executable Path + string pathToSDK = SDKDetector.Instance.LatestSDKBinPath; + string makeappxExecutable = Path.Combine(pathToSDK, "makeappx.exe"); + + // Generate temp path to unpack MSIX package + FileInfo fileInfo = new FileInfo(packageFilePath); + string packageName = Path.GetFileNameWithoutExtension(fileInfo.Name); + string tempPath = Path.GetTempPath(); + string extractedPackageDest = Path.Combine(tempPath, packageName); + + // Delete existing extracted package directories to avoid stalling MakeAppX command + if (Directory.Exists(extractedPackageDest)) + { + TestIndexSetup.DeleteDirectoryContents(Directory.CreateDirectory(extractedPackageDest)); + Directory.Delete(extractedPackageDest); + } + + TestIndexSetup.RunCommand(makeappxExecutable, $"unpack /nv /p {packageFilePath} /d {extractedPackageDest}"); + + string packageSignaturePath = Path.Combine(extractedPackageDest, "AppxSignature.p7x"); + return HashFile(packageSignaturePath); + } + + public static string HashFile(string filePath) + { + FileInfo file; + + try + { + file = new FileInfo(filePath); + } + catch (FileNotFoundException e) + { + Console.WriteLine($"File Not Found: {e.Message}"); + throw; + } + + string hash = string.Empty; + + using (SHA256 mySHA256 = SHA256.Create()) + { + try + { + FileStream fileStream = file.Open(FileMode.Open); + fileStream.Position = 0; + byte[] hashValue = mySHA256.ComputeHash(fileStream); + hash = ConvertHashByteToString(hashValue); + fileStream.Close(); + } + catch (IOException e) + { + Console.WriteLine($"I/O Exception: {e.Message}"); + throw; + } + catch (UnauthorizedAccessException e) + { + Console.WriteLine($"Access Exception: {e.Message}"); + throw; + } + } + + return hash; + } + + public static string ConvertHashByteToString(byte[] array) + { + string hashValue = string.Empty; + + for (int i = 0; i < array.Length; i++) + { + hashValue = hashValue + $"{array[i]:X2}"; + } + + return hashValue; + } + } +} diff --git a/src/AppInstallerCLIE2ETests/TestIndexSetup.cs b/src/AppInstallerCLIE2ETests/TestIndexSetup.cs @@ -0,0 +1,190 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +using System; +using System.Diagnostics; +using System.IO; +using Microsoft.Msix.Utils.ProcessRunner; + +namespace AppInstallerCLIE2ETests +{ + public class TestIndexSetup + { + private const string TestDataName = "TestData"; + private const string ManifestsName = "Manifests"; + private const string PackageName = "Package"; + private const string PublicName = "Public"; + + /// <summary> + /// Generates the Local Test Index to be served by the Localhost Web Server. + /// 1. Copies TestData to a StaticFileRootPath set in Test.runsettings file + /// 2. Copies and signs installer files (EXE or MSIX) + /// 3. Hashes installer Files + /// 4. Replaces manifests with corresponding hash values + /// 5. Generates a source package for TestData using makeappx/signtool + /// </summary> + public static void GenerateTestDirectory() + { + SetupLocalTestDirectory(TestCommon.StaticFileRootPath); + + if (!string.IsNullOrEmpty(TestCommon.ExeInstallerPath)) + { + CopyExeInstallerToTestDirectory(); + } + + if (!string.IsNullOrEmpty(TestCommon.MsixInstallerPath)) + { + CopyMsixInstallerToTestDirectory(); + } + + TestHashHelper.HashInstallers(); + + string manifestDirectoryPath = Path.Combine(TestCommon.StaticFileRootPath, ManifestsName); + TestHashHelper.ReplaceManifestHashToken(manifestDirectoryPath); + + SetupSourcePackage(); + } + + private static void SetupSourcePackage() + { + string indexDestPath = Path.Combine(TestCommon.StaticFileRootPath, PackageName, PublicName); + + DirectoryInfo parentDir = Directory.GetParent(Directory.GetCurrentDirectory()); + string indexCreationToolPath = Path.Combine(parentDir.FullName, Constants.IndexCreationTool); + string winGetUtilPath = Path.Combine(parentDir.FullName, Constants.WinGetUtil); + + // Copy WingetUtil.dll app extension to IndexCreationTool Path + File.Copy(Path.Combine(winGetUtilPath, @"WinGetUtil.dll"), Path.Combine(indexCreationToolPath, @"WinGetUtil.dll"), true); + + try + { + if (!Directory.Exists(indexDestPath)) + { + Directory.CreateDirectory(indexDestPath); + } + + // Generate Index.db file using IndexCreationTool.exe + RunCommand(Path.Combine(indexCreationToolPath, "IndexCreationTool.exe"), $"-d {TestCommon.StaticFileRootPath}", indexDestPath); + + string packageDir = Path.Combine(TestCommon.StaticFileRootPath, PackageName); + string indexPackageDestPath = Path.Combine(TestCommon.StaticFileRootPath, Constants.IndexPackage); + string pathToSDK = SDKDetector.Instance.LatestSDKBinPath; + + // Package Test Source and Sign With Package Certificate + string makeappxExecutable = Path.Combine(pathToSDK, "makeappx.exe"); + string signtoolExecutable = Path.Combine(pathToSDK, "signtool.exe"); + + RunCommand(makeappxExecutable, $"pack /nv /v /o /d {packageDir} /p {indexPackageDestPath}"); + RunCommand(signtoolExecutable, $"sign /a /fd sha256 /f {TestCommon.PackageCertificatePath} {indexPackageDestPath}"); + } + catch (Exception e) + { + Console.WriteLine("Failed. Reason: " + e.Message); + } + } + + private static void CopyExeInstallerToTestDirectory() + { + // Set Exe Test Installer Path + string exeInstallerDestPath = Path.Combine(TestCommon.StaticFileRootPath, Constants.ExeInstaller); + DirectoryInfo exeInstallerDestDir = Directory.CreateDirectory(exeInstallerDestPath); + string exeInstallerFullName = Path.Combine(exeInstallerDestDir.FullName, "AppInstallerTestExeInstaller.exe"); + + // Copy Exe Test Installer to Destination Path + File.Copy(TestCommon.ExeInstallerPath, exeInstallerFullName, true); + TestCommon.ExeInstallerPath = exeInstallerFullName; + + // Sign Installer File + string pathToSDK = SDKDetector.Instance.LatestSDKBinPath; + string signtoolExecutable = Path.Combine(pathToSDK, "signtool.exe"); + RunCommand(signtoolExecutable, $"sign /a /fd sha256 /f {TestCommon.PackageCertificatePath} {exeInstallerFullName}"); + } + + private static void CopyMsixInstallerToTestDirectory() + { + // Set Msix Test Installer Path + string msixInstallerDestPath = Path.Combine(TestCommon.StaticFileRootPath, Constants.MsixInstaller); + DirectoryInfo msixInstallerDestDir = Directory.CreateDirectory(msixInstallerDestPath); + + // Copy Msix Test Installer to Destination Path + string msixInstallerFullName = Path.Combine(msixInstallerDestDir.FullName, "AppInstallerTestMsixInstaller.msix"); + + File.Copy(TestCommon.MsixInstallerPath, msixInstallerFullName, true); + TestCommon.MsixInstallerPath = msixInstallerFullName; + } + + private static void SetupLocalTestDirectory(string staticFileRootPath) + { + DirectoryInfo staticFileRootDir = Directory.CreateDirectory(staticFileRootPath); + + DeleteDirectoryContents(staticFileRootDir); + + string currentDirectory = Environment.CurrentDirectory; + string sourcePath = Path.Combine(currentDirectory, TestDataName); + + CopyDirectory(sourcePath, TestCommon.StaticFileRootPath); + } + + /// <summary> + /// Deletes the contents of a given directory + /// </summary> + /// <param name="directory"></param> + public static void DeleteDirectoryContents(DirectoryInfo directory) + { + foreach (FileInfo file in directory.GetFiles()) + { + file.Delete(); + } + + foreach (DirectoryInfo dir in directory.GetDirectories()) + { + dir.Delete(true); + } + } + + /// <summary> + /// Copies the contents of a given directory from a source path to a destination path + /// </summary> + /// <param name="sourceDirName"></param> + /// <param name="destDirName"></param> + public static void CopyDirectory(string sourceDirName, string destDirName) + { + DirectoryInfo dir = new DirectoryInfo(sourceDirName); + DirectoryInfo[] dirs = dir.GetDirectories(); + + if (!Directory.Exists(destDirName)) + { + Directory.CreateDirectory(destDirName); + } + + FileInfo[] files = dir.GetFiles(); + foreach (FileInfo file in files) + { + string temppath = Path.Combine(destDirName, file.Name); + file.CopyTo(temppath, false); + } + + foreach (DirectoryInfo subdir in dirs) + { + string temppath = Path.Combine(destDirName, subdir.Name); + CopyDirectory(subdir.FullName, temppath); + } + } + + public static void RunCommand(string command, string args) + { + Process p = new Process(); + p.StartInfo = new ProcessStartInfo(command, args); + p.Start(); + p.WaitForExit(); + } + + public static void RunCommand (string command, string args, string workingDirectory) + { + Process p = new Process(); + p.StartInfo = new ProcessStartInfo(command, args); + p.StartInfo.WorkingDirectory = workingDirectory; + p.Start(); + p.WaitForExit(); + } + } +} diff --git a/src/AppInstallerCLIE2ETests/ValidateCommand.cs b/src/AppInstallerCLIE2ETests/ValidateCommand.cs @@ -7,31 +7,34 @@ namespace AppInstallerCLIE2ETests public class ValidateCommand { - [Test] - public void ValidateCommands() + [Test] + public void ValidManifest() { - // Validate a good yaml - var result = TestCommon.RunAICLICommand("validate", TestCommon.GetTestDataFile("Manifests\\TestExeInstaller.yaml")); + var result = TestCommon.RunAICLICommand("validate", TestCommon.GetTestDataFile("Manifests\\TestValidManifest.yaml")); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); Assert.True(result.StdOut.Contains("Manifest validation succeeded.")); + } - // Validate a good yaml with extended character - result = TestCommon.RunAICLICommand("validate", TestCommon.GetTestDataFile("Manifests\\TëstExeInstaller.yaml")); + [Test] + public void ValidManifestWithExtendedCharacter() + { + var result = TestCommon.RunAICLICommand("validate", TestCommon.GetTestDataFile("Manifests\\TëstExeInstaller.yaml")); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); Assert.True(result.StdOut.Contains("Manifest validation succeeded.")); + } - // Validate invalid yaml - result = TestCommon.RunAICLICommand("validate", TestCommon.GetTestDataFile("Manifests\\TestInvalidManifest.yaml")); + [Test] + public void InvalidManifest() + { + var result = TestCommon.RunAICLICommand("validate", TestCommon.GetTestDataFile("Manifests\\TestInvalidManifest.yaml")); Assert.AreEqual(Constants.ErrorCode.ERROR_MANIFEST_VALIDATION_FAILURE, result.ExitCode); Assert.True(result.StdOut.Contains("Manifest validation failed.")); + } - // Validate yaml with warning - result = TestCommon.RunAICLICommand("validate", TestCommon.GetTestDataFile("Manifests\\TestWarningManifest.yaml")); - Assert.AreEqual(Constants.ErrorCode.ERROR_MANIFEST_VALIDATION_WARNING, result.ExitCode); - Assert.True(result.StdOut.Contains("Manifest validation succeeded with warnings.")); - - // Input file not found - result = TestCommon.RunAICLICommand("validate", TestCommon.GetTestDataFile("Manifests\\DoesNotExist")); + [Test] + public void ManifestDoesNotExist() + { + var result = TestCommon.RunAICLICommand("validate", TestCommon.GetTestDataFile("Manifests\\DoesNotExist")); Assert.AreEqual(Constants.ErrorCode.ERROR_FILE_NOT_FOUND, result.ExitCode); Assert.True(result.StdOut.Contains("File does not exist")); } diff --git a/src/AppInstallerTestMsixInstaller/AppInstallerTestMsixInstaller.wapproj b/src/AppInstallerTestMsixInstaller/AppInstallerTestMsixInstaller.wapproj @@ -57,6 +57,36 @@ <AppxPackageSigningEnabled>false</AppxPackageSigningEnabled> <EntryPointProjectUniqueName>..\AppInstallerTestExeInstaller\AppInstallerTestExeInstaller.vcxproj</EntryPointProjectUniqueName> </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'"> + <AppxBundle>Always</AppxBundle> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> + <AppxBundle>Always</AppxBundle> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'"> + <AppxBundle>Always</AppxBundle> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'"> + <AppxBundle>Always</AppxBundle> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'"> + <AppxBundle>Always</AppxBundle> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <AppxBundle>Always</AppxBundle> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'"> + <AppxBundle>Always</AppxBundle> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'"> + <AppxBundle>Always</AppxBundle> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> + <AppxBundle>Always</AppxBundle> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <AppxBundle>Always</AppxBundle> + </PropertyGroup> <ItemGroup> <AppxManifest Include="Package.appxmanifest"> <SubType>Designer</SubType> diff --git a/src/IndexCreationTool/IndexCreationTool.csproj b/src/IndexCreationTool/IndexCreationTool.csproj @@ -1,4 +1,4 @@ -<Project Sdk="Microsoft.NET.Sdk"> +<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> diff --git a/src/IndexCreationTool/Program.cs b/src/IndexCreationTool/Program.cs @@ -65,7 +65,6 @@ namespace IndexCreationTool outputFile.WriteLine($"\"{IndexName}\" \"{IndexPathInPackage}\""); outputFile.WriteLine($"\"{appxManifestPath}\" \"AppxManifest.xml\""); } - RunCommand("makeappx.exe", $"pack /f MappingFile.txt /o /nv /p {IndexPackageName}"); if (!string.IsNullOrEmpty(certPath)) @@ -90,4 +89,4 @@ namespace IndexCreationTool p.WaitForExit(); } } -} +}+ \ No newline at end of file diff --git a/src/LocalhostWebServer/InstallDevCert.ps1 b/src/LocalhostWebServer/InstallDevCert.ps1 @@ -0,0 +1,15 @@ +param( + [Parameter(Mandatory=$true)] + [string]$pfxpath, + + [Parameter(Mandatory=$true)] + [string]$password +) + +Add-Type -AssemblyName System.Security +$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 +$cert.Import($pfxpath, $password, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]"PersistKeySet") +$store = new-object system.security.cryptography.X509Certificates.X509Store -argumentlist "Root", LocalMachine +$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]"ReadWrite") +$store.Add($cert) +$store.Close()+ \ No newline at end of file diff --git a/src/LocalhostWebServer/LocalhostWebServer.csproj b/src/LocalhostWebServer/LocalhostWebServer.csproj @@ -0,0 +1,9 @@ +<Project Sdk="Microsoft.NET.Sdk.Web"> + + <PropertyGroup> + <TargetFramework>netcoreapp3.1</TargetFramework> + <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\LocalhostWebServer\</OutDir> + <Platforms>x64;x86</Platforms> + </PropertyGroup> + +</Project> diff --git a/src/LocalhostWebServer/Program.cs b/src/LocalhostWebServer/Program.cs @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace LocalhostWebServer +{ + using Microsoft.AspNetCore.Builder; + using Microsoft.AspNetCore.Hosting; + using Microsoft.Extensions.Hosting; + using System; + using System.IO; + using Microsoft.Extensions.Configuration; + + public class Program + { + static void Main(string[] args) + { + IConfiguration config = new ConfigurationBuilder() + .AddCommandLine(args) + .Build(); + + Startup.StaticFileRoot = config.GetValue<string>("StaticFileRoot"); + Startup.CertPath = config.GetValue<string>("CertPath"); + Startup.CertPassword = config.GetValue<string>("CertPassword"); + Startup.Port = config.GetValue<Int32>("Port", 5001); + + if (string.IsNullOrEmpty(Startup.StaticFileRoot) || + string.IsNullOrEmpty(Startup.CertPath) || + string.IsNullOrEmpty(Startup.CertPassword)) + { + Console.WriteLine("Usage: LocalhostWebServer.exe StaticFileRoot=<Path to Serve Static Root Directory> " + + "CertPath=<Path to HTTPS Developer Certificate> CertPassword=<Certificate Password> <Port=Port Number>"); + return; + } + + Directory.CreateDirectory(Startup.StaticFileRoot); + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseKestrel(opt => + { + opt.ListenAnyIP(Startup.Port, listOpt => + { + listOpt.UseHttps(Startup.CertPath, Startup.CertPassword); + }); + }); + webBuilder.UseContentRoot(Startup.StaticFileRoot); + webBuilder.UseStartup<Startup>(); + }); + } +}+ \ No newline at end of file diff --git a/src/LocalhostWebServer/Run-LocalhostWebServer.ps1 b/src/LocalhostWebServer/Run-LocalhostWebServer.ps1 @@ -0,0 +1,31 @@ +<# +.SYNOPSIS + Runs the LocalhostWebServer. +.PARAMETER BuildRoot + The root of the build output directory for LocalhostWebServer +.PARAMETER StaticFileRoot + The root of the static files to be served through Localhost +.PARAMETER CertPath + Path to HTTPS Development Certificate File (pfx) +.PARAMETER CertPassword + Secure Password for HTTPS Certificate +#> + +param( + [Parameter(Mandatory=$true)] + [string]$BuildRoot, + + [Parameter(Mandatory=$true)] + [string]$StaticFileRoot, + + [Parameter(Mandatory=$true)] + [string]$CertPath, + + [Parameter(Mandatory=$true)] + [string]$CertPassword +) + +cd $BuildRoot + +Start-Process -FilePath "LocalhostWebServer.exe" -ArgumentList "StaticFileRoot=$StaticFileRoot CertPath=$CertPath CertPassword=$CertPassword" + diff --git a/src/LocalhostWebServer/Startup.cs b/src/LocalhostWebServer/Startup.cs @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace LocalhostWebServer +{ + using Microsoft.AspNetCore.Builder; + using Microsoft.AspNetCore.Hosting; + using Microsoft.AspNetCore.StaticFiles; + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.FileProviders; + using Microsoft.Extensions.Hosting; + + public class Startup + { + public const string StaticFileRequestPath = "/TestKit"; + + public static string StaticFileRoot { get; set; } + + public static string CertPath { get; set; } + + public static string CertPassword { get; set; } + + public static int Port { get; set; } + + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public void ConfigureServices(IServiceCollection services) + { + services.AddControllersWithViews(); + } + + public IConfiguration Configuration { get; } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseHttpsRedirection(); + + //Add .yaml and .msix mappings + var provider = new FileExtensionContentTypeProvider(); + provider.Mappings[".yaml"] = "application/x-yaml"; + provider.Mappings[".msix"] = "application/msix"; + provider.Mappings[".exe"] = "application/x-msdownload"; + provider.Mappings[".msi"] = "application/msi"; + provider.Mappings[".appx"] = "application/vns.ms-appx"; + provider.Mappings[".appxbundle"] = "application/vns.ms-appx"; + + + //Enable static file serving + app.UseStaticFiles(new StaticFileOptions + { + FileProvider = new PhysicalFileProvider(StaticFileRoot), + RequestPath = StaticFileRequestPath, + ContentTypeProvider = provider, + }); + + app.UseDirectoryBrowser(new DirectoryBrowserOptions + { + FileProvider = new PhysicalFileProvider(StaticFileRoot), + RequestPath = StaticFileRequestPath + }); + + app.UseRouting(); + + app.UseAuthorization(); + + app.UseEndpoints(endpoints => + { + endpoints.MapDefaultControllerRoute(); + }); + } + } +}+ \ No newline at end of file