From eac0b6718df18dd714d9ff6a709d7b54f2e5fe2f Mon Sep 17 00:00:00 2001 From: yao-msft <50888816+yao-msft@users.noreply.github.com> Date: Thu, 23 Apr 2020 13:20:08 -0700 Subject: [PATCH] Add E2E tests (#85) Also enabled x86 tests. --- azure-pipelines.yml | 144 +++- src/AppInstallerCLI.sln | 83 +- .../AppInstallerCLIE2ETests.csproj | 32 + src/AppInstallerCLIE2ETests/Constants.cs | 66 ++ src/AppInstallerCLIE2ETests/HashCommand.cs | 36 + src/AppInstallerCLIE2ETests/InstallCommand.cs | 165 ++++ src/AppInstallerCLIE2ETests/SearchCommand.cs | 65 ++ src/AppInstallerCLIE2ETests/SetUpFixture.cs | 127 ++++ src/AppInstallerCLIE2ETests/ShowCommand.cs | 64 ++ src/AppInstallerCLIE2ETests/SourceCommand.cs | 86 +++ src/AppInstallerCLIE2ETests/Test.runsettings | 26 + src/AppInstallerCLIE2ETests/TestCommon.cs | 228 ++++++ .../TestData/AppInstallerTest.cer | Bin 0 -> 1104 bytes .../TestData/IndexPackageInt.cer | Bin 0 -> 1685 bytes .../TestData/IndexPackageManifest.xml | 27 + .../TestData/Manifests/TestBurnInstaller.yaml | 11 + .../TestData/Manifests/TestExeInstaller.yaml | 17 + ...estExeInstaller_InapplicableOsVersion.yaml | 18 + .../TestExeInstaller_Sha256Mismatch.yaml | 17 + .../TestData/Manifests/TestInnoInstaller.yaml | 11 + .../Manifests/TestInvalidManifest.yaml | 17 + .../TestData/Manifests/TestMsiInstaller.yaml | 10 + .../TestData/Manifests/TestMsixInstaller.yaml | 10 + ...stMsixInstaller_SignatureHashMismatch.yaml | 11 + .../TestMsixInstaller_WithSignatureHash.yaml | 11 + .../Manifests/TestNullsoftInstaller.yaml | 11 + .../TestData/PlaceholderPackage.msix | Bin 0 -> 3057 bytes .../ValidateCommand.cs | 29 + .../Package.appxmanifest | 15 +- .../Run-TestsInPackage.ps1 | 5 +- src/AppInstallerCLITests/Sources.cpp | 3 +- .../TEST-AppInstallerCLI-1.xml | 34 - .../AppInstallerTestExeInstaller.vcxproj | 128 ++-- src/AppInstallerTestExeInstaller/main.cpp | 21 +- .../AppInstallerTestMsiInstaller.vdproj | 709 ++++++++++++++++++ .../AppInstallerTestMsixInstaller.wapproj | 78 ++ .../Images/LockScreenLogo.scale-200.png | Bin 0 -> 1430 bytes .../Images/SplashScreen.scale-200.png | Bin 0 -> 7700 bytes .../Images/Square150x150Logo.scale-200.png | Bin 0 -> 2937 bytes .../Images/Square44x44Logo.scale-200.png | Bin 0 -> 1647 bytes ...x44Logo.targetsize-24_altform-unplated.png | Bin 0 -> 1255 bytes .../Images/StoreLogo.png | Bin 0 -> 1451 bytes .../Images/Wide310x150Logo.scale-200.png | Bin 0 -> 3204 bytes .../Package.appxmanifest | 49 ++ .../AppInstallerSQLiteIndexUtilWrapper.cs | 265 +++++++ .../IndexCreationTool.csproj | 9 + src/IndexCreationTool/Program.cs | 92 +++ 47 files changed, 2587 insertions(+), 143 deletions(-) create mode 100644 src/AppInstallerCLIE2ETests/AppInstallerCLIE2ETests.csproj create mode 100644 src/AppInstallerCLIE2ETests/Constants.cs create mode 100644 src/AppInstallerCLIE2ETests/HashCommand.cs create mode 100644 src/AppInstallerCLIE2ETests/InstallCommand.cs create mode 100644 src/AppInstallerCLIE2ETests/SearchCommand.cs create mode 100644 src/AppInstallerCLIE2ETests/SetUpFixture.cs create mode 100644 src/AppInstallerCLIE2ETests/ShowCommand.cs create mode 100644 src/AppInstallerCLIE2ETests/SourceCommand.cs create mode 100644 src/AppInstallerCLIE2ETests/Test.runsettings create mode 100644 src/AppInstallerCLIE2ETests/TestCommon.cs create mode 100644 src/AppInstallerCLIE2ETests/TestData/AppInstallerTest.cer create mode 100644 src/AppInstallerCLIE2ETests/TestData/IndexPackageInt.cer create mode 100644 src/AppInstallerCLIE2ETests/TestData/IndexPackageManifest.xml create mode 100644 src/AppInstallerCLIE2ETests/TestData/Manifests/TestBurnInstaller.yaml create mode 100644 src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller.yaml create mode 100644 src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller_InapplicableOsVersion.yaml create mode 100644 src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller_Sha256Mismatch.yaml create mode 100644 src/AppInstallerCLIE2ETests/TestData/Manifests/TestInnoInstaller.yaml create mode 100644 src/AppInstallerCLIE2ETests/TestData/Manifests/TestInvalidManifest.yaml create mode 100644 src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsiInstaller.yaml create mode 100644 src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsixInstaller.yaml create mode 100644 src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsixInstaller_SignatureHashMismatch.yaml create mode 100644 src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsixInstaller_WithSignatureHash.yaml create mode 100644 src/AppInstallerCLIE2ETests/TestData/Manifests/TestNullsoftInstaller.yaml create mode 100644 src/AppInstallerCLIE2ETests/TestData/PlaceholderPackage.msix create mode 100644 src/AppInstallerCLIE2ETests/ValidateCommand.cs delete mode 100644 src/AppInstallerCLITests/TEST-AppInstallerCLI-1.xml create mode 100644 src/AppInstallerTestMsiInstaller/AppInstallerTestMsiInstaller.vdproj create mode 100644 src/AppInstallerTestMsixInstaller/AppInstallerTestMsixInstaller.wapproj create mode 100644 src/AppInstallerTestMsixInstaller/Images/LockScreenLogo.scale-200.png create mode 100644 src/AppInstallerTestMsixInstaller/Images/SplashScreen.scale-200.png create mode 100644 src/AppInstallerTestMsixInstaller/Images/Square150x150Logo.scale-200.png create mode 100644 src/AppInstallerTestMsixInstaller/Images/Square44x44Logo.scale-200.png create mode 100644 src/AppInstallerTestMsixInstaller/Images/Square44x44Logo.targetsize-24_altform-unplated.png create mode 100644 src/AppInstallerTestMsixInstaller/Images/StoreLogo.png create mode 100644 src/AppInstallerTestMsixInstaller/Images/Wide310x150Logo.scale-200.png create mode 100644 src/AppInstallerTestMsixInstaller/Package.appxmanifest create mode 100644 src/IndexCreationTool/AppInstallerSQLiteIndexUtilWrapper.cs create mode 100644 src/IndexCreationTool/IndexCreationTool.csproj create mode 100644 src/IndexCreationTool/Program.cs diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 689b4a1909..75bd2a7ea4 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -48,6 +48,12 @@ jobs: 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')) @@ -62,33 +68,36 @@ jobs: platform: 'x86' solution: '$(solution)' configuration: '$(buildConfiguration)' - msbuildArgs: '/p:AppxBundlePlatforms="$(buildPlatform)" /p:AppxPackageDir="$(appxPackageDir)" /p:AppxBundle=Always /p:UapAppxPackageBuildMode=StoreUpload' + msbuildArgs: '/p:AppxBundlePlatforms="$(buildPlatform)" + /p:AppxPackageDir="$(appxPackageDir)" + /p:AppxBundle=Always + /p:UapAppxPackageBuildMode=StoreUpload' - task: CmdLine@2 - displayName: Run Tests Unpackaged + displayName: Run Unit Tests Unpackaged x64 inputs: script: | - AppInstallerCLITests.exe -logto AICLI-Unpackaged.log -s -r junit -o TEST-AppInstallerCLI-Unpackaged.xml + AppInstallerCLITests.exe -logto AICLI-Unpackaged-x64.log -s -r junit -o TEST-AppInstallerCLI-Unpackaged-x64.xml workingDirectory: 'src\x64\Release\AppInstallerCLITests\' - task: PublishBuildArtifacts@1 - displayName: Publish Unpackaged Log + displayName: Publish Unit Tests Unpackaged Log x64 inputs: - PathtoPublish: 'src\x64\Release\AppInstallerCLITests\AICLI-Unpackaged.log' + PathtoPublish: 'src\x64\Release\AppInstallerCLITests\AICLI-Unpackaged-x64.log' ArtifactName: 'TestPassUnpackagedLog' publishLocation: 'Container' condition: succeededOrFailed() - task: PublishBuildArtifacts@1 - displayName: Publish Unpackaged Output + displayName: Publish Unit Tests Unpackaged Output x64 inputs: - PathtoPublish: 'src\x64\Release\AppInstallerCLITests\TEST-AppInstallerCLI-Unpackaged.xml' + PathtoPublish: 'src\x64\Release\AppInstallerCLITests\TEST-AppInstallerCLI-Unpackaged-x64.xml' ArtifactName: 'TestPassUnpackagedOutput' publishLocation: 'Container' condition: succeededOrFailed() - task: PowerShell@2 - displayName: Install Dependencies + displayName: Install Tests Dependencies x64 inputs: targetType: 'inline' script: | @@ -96,35 +105,136 @@ jobs: workingDirectory: $(appxPackageDir) - task: PowerShell@2 - displayName: Run Tests Packaged + 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.log -TestResultsTarget x64\Release\TEST-AppInstallerCLI-Packaged.xml -ScriptWait' + 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' - task: PublishBuildArtifacts@1 - displayName: Publish Packaged Log + displayName: Publish Unit Tests Packaged Log x64 inputs: - PathtoPublish: 'src\x64\Release\AICLI-Packaged.log' + PathtoPublish: 'src\x64\Release\AICLI-Packaged-x64.log' ArtifactName: 'TestPassPackagedLog' publishLocation: 'Container' condition: succeededOrFailed() - task: PublishBuildArtifacts@1 - displayName: Publish Packaged Output + displayName: Publish Unit Tests Packaged Output x64 inputs: - PathtoPublish: 'src\x64\Release\TEST-AppInstallerCLI-Packaged.xml' + 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\' + + - 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: Install Tests Dependencies x86 + inputs: + targetType: 'inline' + script: | + Add-AppxPackage AppInstallerCLIPackage_0.0.0.2_Test\Dependencies\x86\Microsoft.VCLibs.x86.14.00.Desktop.appx + workingDirectory: $(appxPackageDir) + + - 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' + + - 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 Test Results + displayName: Publish Unit Test Results inputs: testResultsFormat: 'JUnit' testResultsFiles: '**/TEST-*.xml' failTaskOnFailedTests: true condition: succeededOrFailed() + + - task: VisualStudioTestPlatformInstaller@1 + displayName: Prepare VSTest for E2E Tests + inputs: + packageFeedSelector: 'nugetOrg' + + - task: VSTest@2 + displayName: Run E2E Tests Unpackaged x64 + inputs: + testSelector: 'testAssemblies' + testAssemblyVer2: 'src\AnyCPU\Release\AppInstallerCLIE2ETests\AppInstallerCLIE2ETests.dll' + runSettingsFile: 'src\AnyCPU\Release\AppInstallerCLIE2ETests\Test.runsettings' + overrideTestrunParameters: '-PackagedContext false + -AICLIPath $(system.defaultWorkingDirectory)\src\x64\Release\AppInstallerCLI\AppInstallerCLI.exe' + + - task: VSTest@2 + displayName: Run E2E Tests Packaged x64 + inputs: + testSelector: 'testAssemblies' + testAssemblyVer2: 'src\AnyCPU\Release\AppInstallerCLIE2ETests\AppInstallerCLIE2ETests.dll' + runSettingsFile: 'src\AnyCPU\Release\AppInstallerCLIE2ETests\Test.runsettings' + overrideTestrunParameters: '-PackagedContext true + -AICLIPackagePath $(system.defaultWorkingDirectory)\src\AppInstallerCLIPackage\bin\x64\Release + -AICLIPath AppInstallerCLI\AppInstallerCLI.exe + -LooseFileRegistration true + -InvokeCommandInDesktopPackage true' + + - task: VSTest@2 + displayName: Run E2E Tests Unpackaged x86 + inputs: + testSelector: 'testAssemblies' + testAssemblyVer2: 'src\AnyCPU\Release\AppInstallerCLIE2ETests\AppInstallerCLIE2ETests.dll' + runSettingsFile: 'src\AnyCPU\Release\AppInstallerCLIE2ETests\Test.runsettings' + overrideTestrunParameters: '-PackagedContext false + -AICLIPath $(system.defaultWorkingDirectory)\src\x86\Release\AppInstallerCLI\AppInstallerCLI.exe' + + - task: VSTest@2 + displayName: Run E2E Tests Packaged x86 + inputs: + testSelector: 'testAssemblies' + testAssemblyVer2: 'src\AnyCPU\Release\AppInstallerCLIE2ETests\AppInstallerCLIE2ETests.dll' + runSettingsFile: 'src\AnyCPU\Release\AppInstallerCLIE2ETests\Test.runsettings' + overrideTestrunParameters: '-PackagedContext true + -AICLIPackagePath $(system.defaultWorkingDirectory)\src\AppInstallerCLIPackage\bin\x86\Release + -AICLIPath AppInstallerCLI\AppInstallerCLI.exe + -LooseFileRegistration true + -InvokeCommandInDesktopPackage true' - task: PublishBuildArtifacts@1 displayName: Publish CLI Binary @@ -132,7 +242,7 @@ jobs: PathtoPublish: 'src\x64\Release\AppInstallerCLI\AppInstallerCLI.exe' ArtifactName: 'AppInstallerCLI.exe' publishLocation: 'Container' - + - task: PublishBuildArtifacts@1 displayName: Publish Util Binary inputs: @@ -146,7 +256,7 @@ jobs: PathtoPublish: 'src\x64\Release\WinGetUtil\WinGetUtil.pdb' ArtifactName: 'WinGetUtil.pdb' publishLocation: 'Container' - + - task: ComponentGovernanceComponentDetection@0 displayName: Component Governance inputs: diff --git a/src/AppInstallerCLI.sln b/src/AppInstallerCLI.sln index 9eacbed31a..7e2f0e11c3 100644 --- a/src/AppInstallerCLI.sln +++ b/src/AppInstallerCLI.sln @@ -33,6 +33,16 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AppInstallerTestExeInstalle 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}" +EndProject +Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "AppInstallerTestMsixInstaller", "AppInstallerTestMsixInstaller\AppInstallerTestMsixInstaller.wapproj", "{3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}" +EndProject +Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "AppInstallerTestMsiInstaller", "AppInstallerTestMsiInstaller\AppInstallerTestMsiInstaller.vdproj", "{C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tool", "Tool", "{EA8CD934-0702-4911-A2C5-A40600E616DE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IndexCreationTool", "IndexCreationTool\IndexCreationTool.csproj", "{3B8466CF-4FDD-4329-9C80-91321C4AAC99}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution catch2\catch2.vcxitems*{5295e21e-9868-4de2-a177-fbb97b36579b}*SharedItemsImports = 9 @@ -184,18 +194,82 @@ Global {FB313532-38B0-4676-9303-AB200AA13576}.Release|x64.Build.0 = Release|x64 {FB313532-38B0-4676-9303-AB200AA13576}.Release|x86.ActiveCfg = Release|Win32 {FB313532-38B0-4676-9303-AB200AA13576}.Release|x86.Build.0 = Release|Win32 - {6CB84692-5994-407D-B9BD-9216AF77FE83}.Debug|ARM.ActiveCfg = Debug|Win32 - {6CB84692-5994-407D-B9BD-9216AF77FE83}.Debug|ARM64.ActiveCfg = Debug|Win32 + {6CB84692-5994-407D-B9BD-9216AF77FE83}.Debug|ARM.ActiveCfg = Debug|ARM + {6CB84692-5994-407D-B9BD-9216AF77FE83}.Debug|ARM.Build.0 = Debug|ARM + {6CB84692-5994-407D-B9BD-9216AF77FE83}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {6CB84692-5994-407D-B9BD-9216AF77FE83}.Debug|ARM64.Build.0 = Debug|ARM64 {6CB84692-5994-407D-B9BD-9216AF77FE83}.Debug|x64.ActiveCfg = Debug|x64 {6CB84692-5994-407D-B9BD-9216AF77FE83}.Debug|x64.Build.0 = Debug|x64 {6CB84692-5994-407D-B9BD-9216AF77FE83}.Debug|x86.ActiveCfg = Debug|Win32 {6CB84692-5994-407D-B9BD-9216AF77FE83}.Debug|x86.Build.0 = Debug|Win32 - {6CB84692-5994-407D-B9BD-9216AF77FE83}.Release|ARM.ActiveCfg = Release|Win32 - {6CB84692-5994-407D-B9BD-9216AF77FE83}.Release|ARM64.ActiveCfg = Release|Win32 + {6CB84692-5994-407D-B9BD-9216AF77FE83}.Release|ARM.ActiveCfg = Release|ARM + {6CB84692-5994-407D-B9BD-9216AF77FE83}.Release|ARM.Build.0 = Release|ARM + {6CB84692-5994-407D-B9BD-9216AF77FE83}.Release|ARM64.ActiveCfg = Release|ARM64 + {6CB84692-5994-407D-B9BD-9216AF77FE83}.Release|ARM64.Build.0 = Release|ARM64 {6CB84692-5994-407D-B9BD-9216AF77FE83}.Release|x64.ActiveCfg = Release|x64 {6CB84692-5994-407D-B9BD-9216AF77FE83}.Release|x64.Build.0 = Release|x64 {6CB84692-5994-407D-B9BD-9216AF77FE83}.Release|x86.ActiveCfg = Release|Win32 {6CB84692-5994-407D-B9BD-9216AF77FE83}.Release|x86.Build.0 = Release|Win32 + {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Debug|ARM.ActiveCfg = Debug|Any CPU + {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Debug|x64.ActiveCfg = Debug|Any CPU + {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Debug|x64.Build.0 = Debug|Any CPU + {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Debug|x86.ActiveCfg = Debug|Any CPU + {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Debug|x86.Build.0 = Debug|Any CPU + {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Release|ARM.ActiveCfg = Release|Any CPU + {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Release|ARM64.ActiveCfg = Release|Any CPU + {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Release|x64.ActiveCfg = Release|Any CPU + {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Release|x64.Build.0 = Release|Any CPU + {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Release|x86.ActiveCfg = Release|Any CPU + {3C0269FA-E582-4CA7-9E33-3881A005CA0C}.Release|x86.Build.0 = Release|Any CPU + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Debug|ARM.ActiveCfg = Debug|ARM + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Debug|ARM.Build.0 = Debug|ARM + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Debug|ARM.Deploy.0 = Debug|ARM + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Debug|ARM64.Build.0 = Debug|ARM64 + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Debug|x64.ActiveCfg = Debug|x64 + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Debug|x64.Build.0 = Debug|x64 + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Debug|x64.Deploy.0 = Debug|x64 + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Debug|x86.ActiveCfg = Debug|x86 + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Debug|x86.Build.0 = Debug|x86 + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Debug|x86.Deploy.0 = Debug|x86 + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Release|ARM.ActiveCfg = Release|ARM + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Release|ARM.Build.0 = Release|ARM + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Release|ARM.Deploy.0 = Release|ARM + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Release|ARM64.ActiveCfg = Release|ARM64 + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Release|ARM64.Build.0 = Release|ARM64 + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Release|ARM64.Deploy.0 = Release|ARM64 + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Release|x64.ActiveCfg = Release|x64 + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Release|x64.Build.0 = Release|x64 + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Release|x64.Deploy.0 = Release|x64 + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Release|x86.ActiveCfg = Release|x86 + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Release|x86.Build.0 = Release|x86 + {3E2CBA31-CEBA-4D63-BF52-49C0718E19EA}.Release|x86.Deploy.0 = Release|x86 + {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|x86.ActiveCfg = Debug + {C1624B2F-2BF6-4E28-92FA-1BF85C6B62A8}.Release|ARM.ActiveCfg = Release + {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 + {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Debug|ARM.ActiveCfg = Debug|Any CPU + {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Debug|ARM.Build.0 = Debug|Any CPU + {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Debug|ARM64.Build.0 = Debug|Any CPU + {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Debug|x64.ActiveCfg = Debug|Any CPU + {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Debug|x64.Build.0 = Debug|Any CPU + {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Debug|x86.ActiveCfg = Debug|Any CPU + {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Debug|x86.Build.0 = Debug|Any CPU + {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Release|ARM.ActiveCfg = Release|Any CPU + {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Release|ARM.Build.0 = Release|Any CPU + {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Release|ARM64.ActiveCfg = Release|Any CPU + {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Release|ARM64.Build.0 = Release|Any CPU + {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Release|x64.ActiveCfg = Release|Any CPU + {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Release|x64.Build.0 = Release|Any CPU + {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Release|x86.ActiveCfg = Release|Any CPU + {3B8466CF-4FDD-4329-9C80-91321C4AAC99}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -204,6 +278,7 @@ Global {5295E21E-9868-4DE2-A177-FBB97B36579B} = {60618CAC-2995-4DF9-9914-45C6FC02C995} {8BB94BB8-374F-4294-BCA1-C7811514A6B7} = {60618CAC-2995-4DF9-9914-45C6FC02C995} {6E36DDD7-1602-474E-B1D7-D0A7E1D5AD86} = {8D53D749-D51C-46F8-A162-9371AAA6C2E7} + {3B8466CF-4FDD-4329-9C80-91321C4AAC99} = {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 new file mode 100644 index 0000000000..addd302f80 --- /dev/null +++ b/src/AppInstallerCLIE2ETests/AppInstallerCLIE2ETests.csproj @@ -0,0 +1,32 @@ + + + + netcoreapp3.1 + $(SolutionDir)$(Platform)\$(Configuration)\AppInstallerCLIE2ETests\ + false + + + + + + + + + + + + + + + + PreserveNewest + + + + + + PreserveNewest + + + + diff --git a/src/AppInstallerCLIE2ETests/Constants.cs b/src/AppInstallerCLIE2ETests/Constants.cs new file mode 100644 index 0000000000..71ff10e33a --- /dev/null +++ b/src/AppInstallerCLIE2ETests/Constants.cs @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace AppInstallerCLIE2ETests +{ + public class Constants + { + // Runtime test parameters + public const string PackagedContextParameter = "PackagedContext"; + public const string AICLIPathParameter = "AICLIPath"; + public const string AICLIPackagePathParameter = "AICLIPackagePath"; + public const string VerboseLoggingParameter = "VerboseLogging"; + public const string LooseFileRegistrationParameter = "LooseFileRegistration"; + public const string InvokeCommandInDesktopPackageParameter = "InvokeCommandInDesktopPackage"; + + public const string AppInstallerTestCert = "AppInstallerTest.cer"; + public const string AppInstallerTestCertThumbprint = "d03e7a688b388b1edde8476a627531c49db88017"; + + // Todo: not needed if switch to use prod index for source tests + public const string IndexPackageCert = "IndexPackageInt.cer"; + public const string IndexPackageCertThumbprint = "1da968e670a0257f61628aad20c60c64fdecd41a"; + + public const string AICLIPackageFamilyName = "AppInstallerCLI_8wekyb3d8bbwe"; + public const string AICLIPackageName = "AppInstallerCLI"; + public const string AICLIAppId = "AppInst"; + + // Todo: there's a deployment bug that if the last optional package is removed, the main package is also removed. + // We should remove this when the deployment bug is fixed. + public const string PlaceholderPackageFile = "PlaceholderPackage.msix"; + public const string PlaceholderPackageName = "AppInstallerSQLiteIndex-e2etest-placeholder"; + + public class ErrorCode + { + public const int S_OK = 0; + public const int ERROR_FILE_NOT_FOUND = unchecked((int)0x80070002); + public const int ERROR_NO_RANGES_PROCESSED = unchecked((int)0x80070138); + public const int OPC_E_ZIP_MISSING_END_OF_CENTRAL_DIRECTORY = unchecked((int)0x8051100f); + public const int ERROR_OLD_WIN_VERSION = unchecked((int)0x8007047e); + + // AICLI custom HResults + public const int ERROR_INTERNAL_ERROR = unchecked((int)0x8A150001); + public const int ERROR_INVALID_CL_ARGUMENTS = unchecked((int)0x8A150002); + public const int ERROR_COMMAND_FAILED = unchecked((int)0x8A150003); + public const int ERROR_MANIFEST_FAILED = unchecked((int)0x8A150004); + //public const int ERROR_WORKFLOW_FAILED = unchecked((int)0x8A150005) // Unused, can be repurposed + public const int ERROR_SHELLEXEC_INSTALL_FAILED = unchecked((int)0x8A150006); + //public const int ERROR_RUNTIME_ERROR = unchecked((int)0x8A150007) // Unused, can be repurposed + public const int ERROR_DOWNLOAD_FAILED = unchecked((int)0x8A150008); + public const int ERROR_CANNOT_WRITE_TO_UPLEVEL_INDEX = unchecked((int)0x8A150009); + public const int ERROR_INDEX_INTEGRITY_COMPROMISED = unchecked((int)0x8A15000A); + public const int ERROR_SOURCES_INVALID = unchecked((int)0x8A15000B); + public const int ERROR_SOURCE_NAME_ALREADY_EXISTS = unchecked((int)0x8A15000C); + public const int ERROR_INVALID_SOURCE_TYPE = unchecked((int)0x8A15000D); + public const int ERROR_PACKAGE_IS_BUNDLE = unchecked((int)0x8A15000E); + public const int ERROR_SOURCE_DATA_MISSING = unchecked((int)0x8A15000F); + public const int ERROR_NO_APPLICABLE_INSTALLER = unchecked((int)0x8A150010); + public const int ERROR_INSTALLER_HASH_MISMATCH = unchecked((int)0x8A150011); + public const int ERROR_SOURCE_NAME_DOES_NOT_EXIST = unchecked((int)0x8A150012); + public const int ERROR_SOURCE_ARG_ALREADY_EXISTS = unchecked((int)0x8A150013); + public const int ERROR_NO_APPLICATIONS_FOUND = unchecked((int)0x8A150014); + public const int ERROR_NO_SOURCES_DEFINED = unchecked((int)0x8A150015); + public const int ERROR_MULTIPLE_APPLICATIONS_FOUND = unchecked((int)0x8A150016); + public const int ERROR_NO_MANIFEST_FOUND = unchecked((int)0x8A150017); + } + } +} diff --git a/src/AppInstallerCLIE2ETests/HashCommand.cs b/src/AppInstallerCLIE2ETests/HashCommand.cs new file mode 100644 index 0000000000..6c327a65fd --- /dev/null +++ b/src/AppInstallerCLIE2ETests/HashCommand.cs @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace AppInstallerCLIE2ETests +{ + using NUnit.Framework; + + public class HashCommand + { + [Test] + public void HashCommands() + { + // 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.PlaceholderPackageFile) + " -m"); + Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); + Assert.True(result.StdOut.Contains("08917b781939a7796746b5e2349e1f1d83b6c15599b60cd3f62816f15e565fc4")); + Assert.True(result.StdOut.Contains("223b318c4b1154a1fb72b1bc23422810faa5ce899a8e774ba2a02834b2058f00")); + + // The input is not msix but -m is used + 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")); + Assert.AreEqual(Constants.ErrorCode.ERROR_FILE_NOT_FOUND, result.ExitCode); + Assert.True(result.StdOut.Contains("File does not exist")); + } + } +} \ No newline at end of file diff --git a/src/AppInstallerCLIE2ETests/InstallCommand.cs b/src/AppInstallerCLIE2ETests/InstallCommand.cs new file mode 100644 index 0000000000..7327e08a00 --- /dev/null +++ b/src/AppInstallerCLIE2ETests/InstallCommand.cs @@ -0,0 +1,165 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace AppInstallerCLIE2ETests +{ + using NUnit.Framework; + using System.IO; + + 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. + private const string InstallTestSourceUrl = @"https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData"; + private const string InstallTestSourceName = @"InstallTestSource"; + + private const string InstallTestExeInstalledFile = @"TestExeInstalled.txt"; + private const string InstallTestMsiInstalledFile = @"AppInstallerTestExeInstaller.exe"; + private const string InstallTestMsiProductId = @"{A5D36CF1-1993-4F63-BFB4-3ACD910D36A1}"; + private const string InstallTestMsixName = @"6c6338fe-41b7-46ca-8ba6-b5ad5312bb0e"; + + //[SetUp] + public void Setup() + { + Assert.AreEqual(Constants.ErrorCode.S_OK, TestCommon.RunAICLICommand("source add", $"{InstallTestSourceName} {InstallTestSourceUrl}").ExitCode); + } + + //[TearDown] + public void TearDown() + { + TestCommon.RunAICLICommand("source remove", InstallTestSourceName); + TestCommon.WaitForDeploymentFinish(); + } + + //[Test] + public void InstallCommands() + { + // 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.")); + + // Too many apps match the query + result = TestCommon.RunAICLICommand("install", "AppInstallerTest"); + 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.")); + + // Install test exe + var installDir = TestCommon.GetRandomTestDir(); + result = TestCommon.RunAICLICommand("install", $"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}"); + Assert.AreEqual(Constants.ErrorCode.ERROR_OLD_WIN_VERSION, result.ExitCode); + Assert.True(result.StdOut.Contains("Cannot install application, as it requires a higher OS version")); + 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"); + Assert.AreEqual(Constants.ErrorCode.ERROR_INSTALLER_HASH_MISMATCH, result.ExitCode); + Assert.True(result.StdOut.Contains("Installer hash mismatch")); + 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")); + + // 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}"); + Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); + Assert.True(result.StdOut.Contains("Successfully installed")); + Assert.True(VerifyTestExeInstalled(installDir, "/VERYSILENT")); + + // 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}"); + Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); + Assert.True(result.StdOut.Contains("Successfully installed")); + Assert.True(VerifyTestExeInstalled(installDir, "/quiet")); + + // 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}"); + 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}"); + 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"); + 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"); + 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"); + Assert.AreEqual(Constants.ErrorCode.ERROR_INSTALLER_HASH_MISMATCH, result.ExitCode); + Assert.True(result.StdOut.Contains("Installer hash mismatch")); + 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) + { + if (!File.Exists(Path.Combine(installDir, InstallTestExeInstalledFile))) + { + return false; + } + + if (!string.IsNullOrEmpty(expectedContent)) + { + string content = File.ReadAllText(Path.Combine(installDir, InstallTestExeInstalledFile)); + return content.Contains(expectedContent); + } + + return true; + } + + private bool VerifyTestMsiInstalledAndCleanup(string installDir) + { + if (!File.Exists(Path.Combine(installDir, InstallTestMsiInstalledFile))) + { + return false; + } + + return TestCommon.RunCommand("msiexec.exe", $"/qn /x {InstallTestMsiProductId}"); + } + + private bool VerifyTestMsixInstalledAndCleanup() + { + var result = TestCommon.RunCommandWithResult("powershell", $"Get-AppxPackage {InstallTestMsixName}"); + + if (!result.StdOut.Contains(InstallTestMsixName)) + { + return false; + } + + return TestCommon.RemoveMsix(InstallTestMsixName); + } + } +} \ No newline at end of file diff --git a/src/AppInstallerCLIE2ETests/SearchCommand.cs b/src/AppInstallerCLIE2ETests/SearchCommand.cs new file mode 100644 index 0000000000..e09c8f87e1 --- /dev/null +++ b/src/AppInstallerCLIE2ETests/SearchCommand.cs @@ -0,0 +1,65 @@ +// 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 app 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", "Microsoft -e"); + Assert.AreEqual(Constants.ErrorCode.ERROR_NO_APPLICATIONS_FOUND, result.ExitCode); + Assert.True(result.StdOut.Contains("No app found matching input criteria.")); + } + } +} \ No newline at end of file diff --git a/src/AppInstallerCLIE2ETests/SetUpFixture.cs b/src/AppInstallerCLIE2ETests/SetUpFixture.cs new file mode 100644 index 0000000000..ec904b8b53 --- /dev/null +++ b/src/AppInstallerCLIE2ETests/SetUpFixture.cs @@ -0,0 +1,127 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace AppInstallerCLIE2ETests +{ + using Microsoft.Win32; + using NUnit.Framework; + using System; + using System.IO; + + [SetUpFixture] + public class SetUpFixture + { + private static bool ShouldDisableDevModeOnExit = true; + + [OneTimeSetUp] + public void Setup() + { + // Read TestParameters and set runtime variables + TestCommon.PackagedContext = TestContext.Parameters.Exists(Constants.PackagedContextParameter) && + TestContext.Parameters.Get(Constants.PackagedContextParameter).Equals("true", StringComparison.OrdinalIgnoreCase); + + TestCommon.VerboseLogging = TestContext.Parameters.Exists(Constants.VerboseLoggingParameter) && + TestContext.Parameters.Get(Constants.VerboseLoggingParameter).Equals("true", StringComparison.OrdinalIgnoreCase); + + TestCommon.LooseFileRegistration = TestContext.Parameters.Exists(Constants.LooseFileRegistrationParameter) && + TestContext.Parameters.Get(Constants.LooseFileRegistrationParameter).Equals("true", StringComparison.OrdinalIgnoreCase); + + TestCommon.InvokeCommandInDesktopPackage = TestContext.Parameters.Exists(Constants.InvokeCommandInDesktopPackageParameter) && + TestContext.Parameters.Get(Constants.InvokeCommandInDesktopPackageParameter).Equals("true", StringComparison.OrdinalIgnoreCase); + + if (TestContext.Parameters.Exists(Constants.AICLIPathParameter)) + { + TestCommon.AICLIPath = TestContext.Parameters.Get(Constants.AICLIPathParameter); + } + else + { + if (TestCommon.PackagedContext) + { + // For packaged context, default to AppExecutionAlias + TestCommon.AICLIPath = "AppInst.exe"; + } + else + { + TestCommon.AICLIPath = TestCommon.GetTestFile("AppInstallerCli.exe"); + } + } + + if (TestContext.Parameters.Exists(Constants.AICLIPackagePathParameter)) + { + TestCommon.AICLIPackagePath = TestContext.Parameters.Get(Constants.AICLIPackagePathParameter); + } + else + { + TestCommon.AICLIPackagePath = TestCommon.GetTestFile("AppInstallerCLIPackage.appxbundle"); + } + + if (TestCommon.LooseFileRegistration && TestCommon.InvokeCommandInDesktopPackage) + { + TestCommon.AICLIPath = Path.Combine(TestCommon.AICLIPackagePath, TestCommon.AICLIPath); + } + + ShouldDisableDevModeOnExit = EnableDevMode(true); + + Assert.True(TestCommon.RunCommand("certutil.exe", "-addstore -f \"TRUSTEDPEOPLE\" " + TestCommon.GetTestDataFile(Constants.AppInstallerTestCert))); + Assert.True(TestCommon.RunCommand("certutil.exe", "-addstore -f \"TRUSTEDPEOPLE\" " + TestCommon.GetTestDataFile(Constants.IndexPackageCert))); + + if (TestCommon.PackagedContext) + { + if (TestCommon.LooseFileRegistration) + { + Assert.True(TestCommon.InstallMsixRegister(TestCommon.AICLIPackagePath)); + } + else + { + Assert.True(TestCommon.InstallMsix(TestCommon.AICLIPackagePath)); + } + Assert.True(TestCommon.InstallMsix(TestCommon.GetTestDataFile(Constants.PlaceholderPackageFile))); + } + } + + [OneTimeTearDown] + public void TearDown() + { + if (ShouldDisableDevModeOnExit) + { + EnableDevMode(false); + } + + TestCommon.RunCommand("certutil.exe", $"-delstore \"TRUSTEDPEOPLE\" {Constants.AppInstallerTestCertThumbprint}"); + TestCommon.RunCommand("certutil.exe", $"-delstore \"TRUSTEDPEOPLE\" {Constants.IndexPackageCertThumbprint}"); + + if (TestCommon.PackagedContext) + { + TestCommon.RemoveMsix(Constants.PlaceholderPackageName); + TestCommon.RemoveMsix(Constants.AICLIPackageName); + } + } + + // Returns whether there's a change to the dev mode state after execution + private bool EnableDevMode(bool enable) + { + var appModelUnlockKey = Registry.LocalMachine.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock"); + + if (enable) + { + var value = appModelUnlockKey.GetValue("AllowDevelopmentWithoutDevLicense"); + if (value == null || (Int32)value == 0) + { + appModelUnlockKey.SetValue("AllowDevelopmentWithoutDevLicense", 1, RegistryValueKind.DWord); + return true; + } + } + else + { + var value = appModelUnlockKey.GetValue("AllowDevelopmentWithoutDevLicense"); + if (value != null && ((UInt32)value) != 0) + { + appModelUnlockKey.SetValue("AllowDevelopmentWithoutDevLicense", 0, RegistryValueKind.DWord); + return true; + } + } + + return false; + } + } +} diff --git a/src/AppInstallerCLIE2ETests/ShowCommand.cs b/src/AppInstallerCLIE2ETests/ShowCommand.cs new file mode 100644 index 0000000000..ab481db52b --- /dev/null +++ b/src/AppInstallerCLIE2ETests/ShowCommand.cs @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace AppInstallerCLIE2ETests +{ + using NUnit.Framework; + using System.Threading; + + public class ShowCommand + { + // Todo: use created test source when available + private const string ShowTestSourceUrl = @"https://winget-int.azureedge.net/cache"; + private const string ShowTestSourceName = @"ShowTestSource"; + + [SetUp] + public void Setup() + { + Assert.AreEqual(Constants.ErrorCode.S_OK, TestCommon.RunAICLICommand("source add", $"{ShowTestSourceName} {ShowTestSourceUrl}").ExitCode); + } + + [TearDown] + public void TearDown() + { + TestCommon.RunAICLICommand("source remove", ShowTestSourceName); + + TestCommon.WaitForDeploymentFinish(); + } + + [Test] + public void ShowCommands() + { + // Show with no arg lists every app and a warning message + var result = TestCommon.RunAICLICommand("show", ""); + 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("Microsoft.PowerToys")); + Assert.True(result.StdOut.Contains("Microsoft.VisualStudioCode")); + + // Show with multiple search matches shows a "please refine input" + result = TestCommon.RunAICLICommand("show", "Microsoft"); + 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("Microsoft.PowerToys")); + Assert.True(result.StdOut.Contains("Microsoft.VisualStudioCode")); + + // Show with 0 search match shows a "please refine input" + result = TestCommon.RunAICLICommand("show", "DoesNotExist"); + Assert.AreEqual(Constants.ErrorCode.ERROR_NO_APPLICATIONS_FOUND, result.ExitCode); + Assert.True(result.StdOut.Contains("No app found matching input criteria.")); + + // Show with 1 search match shows detailed manifest info + result = TestCommon.RunAICLICommand("show", "VisualStudioCode"); + Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); + Assert.True(result.StdOut.Contains("Microsoft.VisualStudioCode")); + Assert.True(result.StdOut.Contains("Visual Studio Code")); + + // Show with --versions list the versions + result = TestCommon.RunAICLICommand("show", "VisualStudioCode --versions"); + Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); + Assert.True(result.StdOut.Contains("Microsoft.VisualStudioCode")); + Assert.True(result.StdOut.Contains("1.41.1")); + } + } +} \ No newline at end of file diff --git a/src/AppInstallerCLIE2ETests/SourceCommand.cs b/src/AppInstallerCLIE2ETests/SourceCommand.cs new file mode 100644 index 0000000000..4c118f4167 --- /dev/null +++ b/src/AppInstallerCLIE2ETests/SourceCommand.cs @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace AppInstallerCLIE2ETests +{ + using NUnit.Framework; + + public class SourceCommand + { + // Todo: switch to use prod index when available + private const string SourceTestSourceUrl = @"https://winget-int.azureedge.net/cache"; + private const string SourceTestSourceName = @"SourceTestSource"; + + [TearDown] + public void TearDown() + { + TestCommon.RunAICLICommand("source remove", SourceTestSourceName); + + TestCommon.WaitForDeploymentFinish(); + } + + [Test] + public void SourceCommands() + { + // Add test source should succeed + var result = TestCommon.RunAICLICommand("source add", $"{SourceTestSourceName} {SourceTestSourceUrl}"); + Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); + Assert.True(result.StdOut.Contains("Done")); + + // Add source with duplicate name should fail + 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")); + + // Add source with invalid url should fail + 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")); + + // List with no args should list all available sources + 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}"); + 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("AppInstallerSQLiteIndex-int")); + Assert.True(result.StdOut.Contains("Updated")); + + // List when source name does not match + 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}"); + 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"); + 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"); + 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}"); + Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); + Assert.True(result.StdOut.Contains("Done")); + + TestCommon.WaitForDeploymentFinish(); + + // List should show no source available + result = TestCommon.RunAICLICommand("source list", ""); + Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); + Assert.True(result.StdOut.Contains("There are no sources configured.")); + } + } +} \ No newline at end of file diff --git a/src/AppInstallerCLIE2ETests/Test.runsettings b/src/AppInstallerCLIE2ETests/Test.runsettings new file mode 100644 index 0000000000..14aeff2f4f --- /dev/null +++ b/src/AppInstallerCLIE2ETests/Test.runsettings @@ -0,0 +1,26 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AppInstallerCLIE2ETests/TestCommon.cs b/src/AppInstallerCLIE2ETests/TestCommon.cs new file mode 100644 index 0000000000..c84a383d6a --- /dev/null +++ b/src/AppInstallerCLIE2ETests/TestCommon.cs @@ -0,0 +1,228 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace AppInstallerCLIE2ETests +{ + using NUnit.Framework; + using System; + using System.Diagnostics; + using System.IO; + using System.Threading; + + public class TestCommon + { + public static string AICLIPath { get; set; } + + public static string AICLIPackagePath { get; set; } + + public static bool PackagedContext { get; set; } + + public static bool VerboseLogging { get; set; } + + public static bool LooseFileRegistration { get; set; } + + public static bool InvokeCommandInDesktopPackage { get; set; } + + public struct RunCommandResult + { + public int ExitCode; + public string StdOut; + public string StdErr; + } + + public static RunCommandResult RunAICLICommand(string command, string parameters, string stdIn = null, int timeOut = 60000) + { + string inputMsg = + "AICLI path: " + AICLIPath + + " Command: " + command + + " Parameters: " + parameters + + (string.IsNullOrEmpty(stdIn) ? "" : " StdIn: " + stdIn) + + " Timeout: " + timeOut; + + TestContext.Out.WriteLine($"Starting command run. {inputMsg} InvokeCommandInDesktopPackage: {InvokeCommandInDesktopPackage}"); + + if (InvokeCommandInDesktopPackage) + { + return RunAICLICommandViaInvokeCommandInDesktopPackage(command, parameters, stdIn, timeOut); + } + else + { + return RunAICLICommandViaDirectProcess(command, parameters, stdIn, timeOut); + } + } + + public static RunCommandResult RunAICLICommandViaDirectProcess(string command, string parameters, string stdIn = null, int timeOut = 60000) + { + RunCommandResult result = new RunCommandResult(); + Process p = new Process(); + p.StartInfo = new ProcessStartInfo(AICLIPath, command + ' ' + parameters); + p.StartInfo.UseShellExecute = false; + p.StartInfo.RedirectStandardOutput = true; + p.StartInfo.RedirectStandardError = true; + + if (!string.IsNullOrEmpty(stdIn)) + { + p.StartInfo.RedirectStandardInput = true; + } + + p.Start(); + + if (!string.IsNullOrEmpty(stdIn)) + { + p.StandardInput.Write(stdIn); + } + + if (p.WaitForExit(timeOut)) + { + result.ExitCode = p.ExitCode; + result.StdOut = p.StandardOutput.ReadToEnd(); + result.StdErr = p.StandardError.ReadToEnd(); + + TestContext.Out.WriteLine("Command run completed with exit code: " + result.ExitCode); + + if (!string.IsNullOrEmpty(result.StdErr)) + { + TestContext.Error.WriteLine("Command run error. Error: " + result.StdErr); + } + + if (VerboseLogging && !string.IsNullOrEmpty(result.StdOut)) + { + TestContext.Out.WriteLine("Command run output. Output: " + result.StdOut); + } + } + else + { + throw new TimeoutException("Command run timed out."); + } + + return result; + } + + // This method is used when the test is run in an OS that does not support AppExecutionAlias. E,g, our build machine. + // There is not any existing API that'll activate a packaged app and wait for result, and not possible to capture the stdIn and stdOut. + // This method tries to call Invoke-CommandInDesktopPackage PS command to make test executable run in packaged context. + // Since Invoke-CommandInDesktopPackage just launches the executable and return, we use cmd pipe to get execution results. + // The final constructed command will look like: + // Invoke-CommandInDesktopPackage ...... -Command cmd.exe -Args '-c ' + // where will look like: "echo stdIn | appinst.exe args > stdout.txt 2> stderr.txt & echo %ERRORLEVEL% > exitcode.txt" + // Then this method will read the piped result and return as RunCommandResult. + public static RunCommandResult RunAICLICommandViaInvokeCommandInDesktopPackage(string command, string parameters, string stdIn = null, int timeOut = 60000) + { + string cmdCommandPiped = ""; + if (!string.IsNullOrEmpty(stdIn)) + { + cmdCommandPiped += $"echo {stdIn} | "; + } + + string workDirectory = GetRandomTestDir(); + string exitCodeFile = Path.Combine(workDirectory, "ExitCode.txt"); + string stdOutFile = Path.Combine(workDirectory, "StdOut.txt"); + string stdErrFile = Path.Combine(workDirectory, "StdErr.txt"); + + cmdCommandPiped += $"{AICLIPath} {command} {parameters} > {stdOutFile} 2> {stdErrFile} & call echo %^ERRORLEVEL% > {exitCodeFile}"; + + string psCommand = $"Invoke-CommandInDesktopPackage -PackageFamilyName {Constants.AICLIPackageFamilyName} -AppId {Constants.AICLIAppId} -PreventBreakaway -Command cmd.exe -Args '/c \"{cmdCommandPiped}\"'"; + + var psInvokeResult = RunCommandWithResult("powershell", psCommand); + + if (psInvokeResult.ExitCode != 0) + { + // PS invocation failed, return result and no need to check piped output. + return psInvokeResult; + } + + // The PS command just launches the app and immediately returns, we'll have to wait for up to the timeOut specified here + int waitedTime = 0; + while (!File.Exists(exitCodeFile) && waitedTime <= timeOut) + { + Thread.Sleep(1000); + waitedTime += 1000; + } + + RunCommandResult result = new RunCommandResult(); + + result.ExitCode = File.Exists(exitCodeFile) ? int.Parse(File.ReadAllText(exitCodeFile).Trim()) : unchecked((int)0x80004005); + result.StdOut = File.Exists(stdOutFile) ? File.ReadAllText(stdOutFile) : ""; + result.StdErr = File.Exists(stdErrFile) ? File.ReadAllText(stdErrFile) : ""; + + return result; + } + + public static bool RunCommand(string fileName, string args, int timeOut = 60000) + { + return RunCommandWithResult(fileName, args, timeOut).ExitCode == 0; + } + + public static RunCommandResult RunCommandWithResult(string fileName, string args, int timeOut = 60000) + { + Process p = new Process(); + p.StartInfo = new ProcessStartInfo(fileName, args); + p.StartInfo.RedirectStandardOutput = true; + p.StartInfo.RedirectStandardError = true; + p.Start(); + + RunCommandResult result = new RunCommandResult(); + if (p.WaitForExit(timeOut)) + { + result.ExitCode = p.ExitCode; + result.StdOut = p.StandardOutput.ReadToEnd(); + result.StdErr = p.StandardError.ReadToEnd(); + + if (VerboseLogging) + { + TestContext.Out.WriteLine($"Command run finished. {fileName} {args} {timeOut}. Output: {result.StdOut} Error: {result.StdErr}"); + } + } + else + { + throw new TimeoutException($"Command run timed out. {fileName} {args} {timeOut}"); + } + + return result; + } + + public static string GetTestFile(string fileName) + { + return Path.Combine(TestContext.CurrentContext.TestDirectory, fileName); + } + + public static string GetTestDataFile(string fileName) + { + return GetTestFile(Path.Combine("TestData", fileName)); + } + + public static string GetRandomTestDir() + { + string randDir = Path.Combine(TestContext.CurrentContext.TestDirectory, Path.Combine("WorkDirectory", Path.GetRandomFileName())); + Directory.CreateDirectory(randDir); + return randDir; + } + + public static bool InstallMsix(string file) + { + return RunCommand("powershell", $"Add-AppxPackage \"{file}\""); + } + + public static bool InstallMsixRegister(string packagePath) + { + string manifestFile = Path.Combine(packagePath, "AppxManifest.xml"); + return RunCommand("powershell", $"Add-AppxPackage -Register \"{manifestFile}\""); + } + + public static bool RemoveMsix(string name) + { + return RunCommand("powershell", $"Get-AppxPackage \"{name}\" | Remove-AppxPackage"); + } + + public static void WaitForDeploymentFinish() + { + if (PackagedContext) + { + // Since we are doing a lot index add/remove, and some of the methods are fire and forget. + // Sometimes process start will fail because app is updating. + // Or index package is not completely added, removed. + Thread.Sleep(5000); + } + } + } +} diff --git a/src/AppInstallerCLIE2ETests/TestData/AppInstallerTest.cer b/src/AppInstallerCLIE2ETests/TestData/AppInstallerTest.cer new file mode 100644 index 0000000000000000000000000000000000000000..02f5ddf96c4df5358ce0923a2f794405b5825637 GIT binary patch literal 1104 zcmXqLV(~F(VzyYo%*4pVB#UR%uKSZ3-ibnU`LYpJymwzy}g!7iJGiP07vAOEHu)kO7Hs35)t> zCKu%w=ckn@IOi7?}*8JHRv7y_ZW z0T4tDkh_`~l?-^7U=E0=hlbU5NYi--Gg7xO%^PfEJ zX2vn+ZaI2qesSCO%Kn<`sx6aZAJ09x{o$X^MXz^==f>Ttql)6;4x6PcJ9 z85kEg-ZyBxW55qg0kXo3jQ?3!4S?y4!9X4)pvod)AjZa_&Bn;e%FfKp#sy@tFgBTU zG4mQUE(fV#WNDml&^V_-;NWtFNAKo)%!_BI57|BMVK-`l^; z$l|!jXj1&_%CbYVjQ+Uo;t%hgtv}_!q2J8xk%N9%L=!%57_O&oFo zzrq?_rZ+qh^=kWZ-C^xkwv3duCzI5ch;}UT&b<*Y5nr*9>(|!@mwxI2FdN_cthgSj(!=1ebdec+~V>Jj)~MRCzdP z>-^{~Yx!3^PI~w{rtPVrzREe+?qgY7k1x{~iG zG%Xf9>_2hdH%8ZJC*iQqPuQ$vQ`|njc{bmoVq;3f<>^K*^&Bpk=w0xhc_Pzz`lbo5 z70cs7{x+`6G7tWF{Ks$ZM?KPW-=4@kznO`dk%4h>6H|&o6H|f#H!yr<`B_+)nb;c) zgh3ot79ImGHV$nzMpjmKW@ZCfkRTt67>h`T!MlLkZEkgc_}3KlE}9vTC47k8AOIvS z$l__>zQonQ*-+C!9Vo!UEv$fuG5>;8NPHG61eB&0mEG#u%L16g2q*C8W|-e1y=g{$-o3uke#WYT$G~^O2Vo}2F{K^BFa$1P*V>m+GY<` znOh9x>E*(bo?dc(u0BX7P#kCm9s_J)R*|LMps^bkzKo14^#-*DCNRDM6NWbuGZV3T zqr|`!NtY$mMdjt?xIKg|G)fHY*f@ca&BEAZF3QegXrRxg4&!pP-)bvues`0x>13;P z`cV~*L&zlm_d||n9$Vqm6Z&luu zE1Ek?PETt&5hrN3!^(thQ-dbwfju?y0sPxum8{umx79@OY_olp+qK$6?kBZLO#zV~ z4%K~biaWgG=Lw%bd@NrSo#tJ8++^|ML!U(d;-#nlzdx@bySsi~b^E&v_NBWX$uhfK z?Yf&bO|zGbhfw%PqJ*Ywcl_GxP;JO-ADmFH_DZ@kQXbL@S? zuXkFnrOLDR^kyf1{2jXJ!DMxr8Buyuf{%MzR)&e&Oe&Mt_{&(SXnC@3JI|8mhZZRP zp1k8kjh^V2`0%{?+OmI3J9n-=-k|#K>mk_|i5~g;@84McV7i=Ue_teY`3CQU+HZHL z?>etACtS95UuxO>waeJwaNb|=aI&QLP zmp7Ts;wqzl-~QV3Mt;M)N1th)UAnjD&*>*D^Mssg^(LImj^x{L^?}C;6ThY3C2HlK zTw(Lu`BP8j*4xa|2ivsQ?9uglR5N>t)q^Dwl8P+d_jVrA@SD)Cy_`{LeN=LDgZr%{ zG2YOCWZl + + + + + + AppInstallerSQLiteIndex for AppInstallerCLI. + Microsoft Corporation + Assets\AppPackageStoreLogo.png + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestBurnInstaller.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestBurnInstaller.yaml new file mode 100644 index 0000000000..a7d0493c21 --- /dev/null +++ b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestBurnInstaller.yaml @@ -0,0 +1,11 @@ +Id: AppInstallerTest.TestBurnInstaller +Name: TestBurnInstaller +Version: 1.0.0.0 +Publisher: AppInstallerTest +Installers: + - Arch: x86 + Url: https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestExeInstaller.exe + Sha256: 7c616e2fe3853b555ddea4cb50bd307da1dc47898a5fbc3a8646a470107802ab + InstallerType: burn + Switches: + InstallLocation: /InstallDir diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller.yaml new file mode 100644 index 0000000000..5acb05ed00 --- /dev/null +++ b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller.yaml @@ -0,0 +1,17 @@ +Id: AppInstallerTest.TestExeInstaller +Name: TestExeInstaller +Version: 1.0.0.0 +Publisher: AppInstallerTest +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 + InstallLocation: /InstallDir diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller_InapplicableOsVersion.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller_InapplicableOsVersion.yaml new file mode 100644 index 0000000000..fede6133d0 --- /dev/null +++ b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller_InapplicableOsVersion.yaml @@ -0,0 +1,18 @@ +Id: AppInstallerTest.InapplicableOsVersion +Name: InapplicableOsVersion +Version: 1.0.0.0 +Publisher: AppInstallerTest +MinOSVersion: 11.0.0.0 +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 + InstallLocation: /InstallDir diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller_Sha256Mismatch.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller_Sha256Mismatch.yaml new file mode 100644 index 0000000000..126d492be4 --- /dev/null +++ b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller_Sha256Mismatch.yaml @@ -0,0 +1,17 @@ +Id: AppInstallerTest.TestExeSha256Mismatch +Name: TestExeSha256Mismatch +Version: 1.0.0.0 +Publisher: AppInstallerTest +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 + InstallLocation: /InstallDir diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestInnoInstaller.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestInnoInstaller.yaml new file mode 100644 index 0000000000..b39764bf74 --- /dev/null +++ b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestInnoInstaller.yaml @@ -0,0 +1,11 @@ +Id: AppInstallerTest.TestInnoInstaller +Name: TestInnoInstaller +Version: 1.0.0.0 +Publisher: AppInstallerTest +Installers: + - Arch: x86 + Url: https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestExeInstaller.exe + Sha256: 7c616e2fe3853b555ddea4cb50bd307da1dc47898a5fbc3a8646a470107802ab + InstallerType: inno + Switches: + InstallLocation: /InstallDir diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestInvalidManifest.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestInvalidManifest.yaml new file mode 100644 index 0000000000..b89bce4c3f --- /dev/null +++ b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestInvalidManifest.yaml @@ -0,0 +1,17 @@ +Id: TestInvalidManifest TestInvalidManifest +Name: TestInvalidManifest +Version: 1.0.0.0 +Publisher: AppInstallerTest +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 + InstallLocation: /InstallDir diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsiInstaller.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsiInstaller.yaml new file mode 100644 index 0000000000..3c01c6bb11 --- /dev/null +++ b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsiInstaller.yaml @@ -0,0 +1,10 @@ +Id: AppInstallerTest.TestMsiInstaller +Name: TestMsiInstaller +Version: 1.0.0.0 +Publisher: AppInstallerTest +Installers: + - Arch: x86 + Url: https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestMsiInstaller.msi + Sha256: 18a07fadd84fd66fce094e323a51afba648fd8c2a826573d61b60960d7e35e63 + InstallerType: msi + diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsixInstaller.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsixInstaller.yaml new file mode 100644 index 0000000000..b255a67381 --- /dev/null +++ b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsixInstaller.yaml @@ -0,0 +1,10 @@ +Id: AppInstallerTest.TestMsixInstaller +Name: TestMsixInstaller +Version: 1.0.0.0 +Publisher: AppInstallerTest +Installers: + - Arch: x86 + Url: https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestMsixInstaller.msix + Sha256: 714c861a52478bfa44228739c500c9429f4e75c7b78d48cac06bfb8f62bad627 + InstallerType: msix + diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsixInstaller_SignatureHashMismatch.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsixInstaller_SignatureHashMismatch.yaml new file mode 100644 index 0000000000..844e934390 --- /dev/null +++ b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsixInstaller_SignatureHashMismatch.yaml @@ -0,0 +1,11 @@ +Id: AppInstallerTest.TestMsixSignatureHashMismatch +Name: TestMsixSignatureHashMismatch +Version: 1.0.0.0 +Publisher: AppInstallerTest +Installers: + - Arch: x86 + Url: https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestMsixInstaller.msix + Sha256: 714c861a52478bfa44228739c500c9429f4e75c7b78d48cac06bfb8f62bad626 + SignatureSha256: d8a54b79a9c5956df5b338fdaf37f48e56316465defd182cbe64d8e5d3d53d4d + InstallerType: msix + diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsixInstaller_WithSignatureHash.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsixInstaller_WithSignatureHash.yaml new file mode 100644 index 0000000000..d5e6f7c1ab --- /dev/null +++ b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestMsixInstaller_WithSignatureHash.yaml @@ -0,0 +1,11 @@ +Id: AppInstallerTest.TestMsixWithSignatureHash +Name: TestMsixWithSignatureHash +Version: 1.0.0.0 +Publisher: AppInstallerTest +Installers: + - Arch: x86 + Url: https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestMsixInstaller.msix + Sha256: 714c861a52478bfa44228739c500c9429f4e75c7b78d48cac06bfb8f62bad627 + SignatureSha256: d8a54b79a9c5956df5b338fdaf37f48e56316465defd182cbe64d8e5d3d53d4e + InstallerType: msix + diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestNullsoftInstaller.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestNullsoftInstaller.yaml new file mode 100644 index 0000000000..d4c7476dce --- /dev/null +++ b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestNullsoftInstaller.yaml @@ -0,0 +1,11 @@ +Id: AppInstallerTest.TestNullsoftInstaller +Name: TestNullsoftInstaller +Version: 1.0.0.0 +Publisher: AppInstallerTest +Installers: + - Arch: x86 + Url: https://github.com/microsoft/appinstaller-cli/raw/master/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestExeInstaller.exe + Sha256: 7c616e2fe3853b555ddea4cb50bd307da1dc47898a5fbc3a8646a470107802ab + InstallerType: nullsoft + Switches: + InstallLocation: /InstallDir diff --git a/src/AppInstallerCLIE2ETests/TestData/PlaceholderPackage.msix b/src/AppInstallerCLIE2ETests/TestData/PlaceholderPackage.msix new file mode 100644 index 0000000000000000000000000000000000000000..cea148d19b668033c23c8d51096bd670764d0b3b GIT binary patch literal 3057 zcmai0c{tQv8y-w{vWzHAAtGy*VeAsJj>#?}S*FP{V=H=P-**OCLRye9w(KEWwjr;< zRF=sug;B_seB)Bz+xva*cYV+AkLNt+oag+mb6?MS?i+4E1C#*JQ$F{ABskzVW21~O zq0xRu4jxDsXKx=#KXG ztH2^buV$003#gG>6|NstWKpC)Wc31Suwq}CiF!B=rNlQEsDymZo2UHQwfN*hv%azM z46kIK9~E#o-QdVe8VDi)l3jb%=I@FP7uKKxCB z^@T-$^N`6ORtCq#(%U?MoNMn~okTlDeA7d~-`cz#A&-^a7cJ7PgaaJe;g@D5$`dg; z-TI9jZkpV0dkeX*oESSLcv@WP+y`~0QjAT{ZCsUXmC>1cF;6Wu;ECS-Z^grdZ5kcV z!Z!&il~kXF>Njxb?ewFl?Zdd1gkj0HHZt)NM68HQM<1(OxhKya{A#~i{|cJe_~+7u z;@T>={3;Rkxh8@wHeU25@qA6mJ7w#YVGd@#yF#=k z)M>}op_BwOI^M9jSt$%2KQ$joZtMYj&^g@?P|6BiY4#Y8$jx!DHv{jhK5JPaW!_>~ z?RAyi$ow%JvE!Y3#rxoFHM)jmTz+JH`o^0&nOREgWAetaT2eZMNRF_i1 z5{gm_2M06&xB(r#(1Cg$fcmIVwt+_;{(q}T(+%b5YUF@EtRj^p1LKa1Y~f_x?{uz; z0^jLbv_)W}`anT?5f$L40YTW!Q{(*dMz71eFNhY6mM!FD8J$p`EWn+9SQSar0ZNv8 zhD$?2n_8R@4}u?Z7joo6Qo|}Mbd!=&%@KGb$$KEbS!gwB%QC#aD*YO?)LhXD;hJQC zjrq6-juCk>=h$BTk!q6h?E;~$b~mcqvvXFl_A+N@8oScDHq{YDPh9j2lP<>4mqV2v zoGl)Pl#DNVwhsLWP{rn>5ko4}KK6A%pWWKOxo@SMF0l$I)fc73byqztQ=Db(*256}BFS?6rU5)ri^KN6A^E0cTnh&3K&y@HkGaN`)o;C6OxmQG~0URhIgmx|E z&mNi+4W9-F8#nnK*wYJd&P6ItBCjvg(tx-)O>ptjbW^7m^n@#HGU4_$D>bz#JTbg> zr>n?$=oosEE)97)k9;#yy2Gb1h6Bq! zR_XW3^W-E;RoQ$hocRfVmCFQb2-zZoROp+ZOJx?)l9V72EJOrSs;8gYwhvW_juHuF z;6NY z<(;%&ufTay&jG%Or<7g^htn^%vR&f~WbEu{bz&%_@^Ju#(gV|6)P3R%Kb`U|<-R>> zXV141!rxAy>U^EQk{B!70E3;eJuZxoulM`B0AgzU!7TAI&Y2kWyvVD2Thm1VGU`Df zZroCT+d=5lkWv*@g72-h&5@QRciu5&4cy%S05qu%vVHq@n|)YA9)TFCy`A?y)OxT{ zmd-2k40D$a8j3ppE<^H>kLP^C0|vvgsEAqGT~*|@bXFGohHp2VS|OJzQXgxFeUF9N za||oeZiz{>UKI|0!V0+3&&b9T>X5B_e}G>RanOa5)%@Ie*BwU9sHLbX1hjaNF2Z4& z77@*>|FpxSj0Y@k!#ua-bT?4zMl#y|sc!U8FhM}~F~;`$F@Avpz%T&I%`THW%~P#l z3*u*t9;pUJM8&r6q+F`vI{URJXfC9XF`Xq?y356pht82~VeUf13Akvz2(TXCk64Yk z+^?OX-Xy8pB@=qN4|oz5>G@vSf1(biP(O6LwK2X44ROiADj+yfYWGF&`azZ5F}Dh9 zi7&=#Jx1b0YsQv)H=YW{NBJh^Gv)ZOK5y9S&fv~`ahs$9mw@&QBKr>$bE}_}@+oLUy zdt~QX<#r&2XYD5OjkecC75*fsy1o>OiV7bgol4Wu{WJ>`+(4ey+X}o_*c>>wU-`n+ zG9${5PF{69zoy`IUDsS#>XrmM>wnV4HVl z#9+?x_gulHu#2)i5PuU4uLMP}vkqnJ%UwY{mETe8*<9249$I{H7hjQhkgt)fJ(lp{ z%>CSE`xZKx#7sZ<#6x@_YVy%?p4ZsLb)9t;&98IZjSpFfE63GqypuQk?hAs4+UFq; z7w*L1s#p`Gmj%hY{bHY@LqcQksOJjkc%|IeeU(&Vye#x}B4>J!ydaEE-K-kDZof8Q ze=KXE!euQ@4kB8F!30b!H)yTsGF^RM;xyGs4j8l?HZK_qS1noC49MAzx-n%mhLJf~ zijyeVYb`5GcGI`BFeFr@JB;2Lt!x3(F<>M6Oqo1b%6Mab>`F#Bu)m!#5uP-)DX`rg zK{@pq$do&r=3cnrgfEVtpIqsC2{sb==+AM`geqU}!o_+9@2$aXaN&>hrIMyE@=jHR z^gD$>ckmS(Qu5!7)g^TS)j~vA+YJqXn0l-=Rhx)G5Y2mJzJRtNgZO|<@N`jxNS7AG zx2dc|cVD>(^tol4S57B%Z&EueFN>?*@`1L$ouM`!Q5!PD#-HV7m3&HR#flhqsx)>r zSGErCHS-0PzYuj#Si3&_ndC@u>7++3CRL9(+=r28zTn|D#jttV-qIk@a0KU*xk`{_ zi0<7;DCtG)f%4_7{Lw6N-u&lCfsQ%E_QB+O>D}F1DtAfC{x+S@pyeiW)=mm!t(}dW zZt%(=Z9)xa5#o$Q^?{~byk4m6?qr8pNwhW9h+{*O-`=yS+Baa>_G)%LHDwxzT-^LM&EBC39jUk5C87;RMZlHzeMRT!Eq=y z4n^tT?LQ?d+~Duozex6wVE>-2LlH5D*}qGZqwN1pz<>QandTqq`1b?;iKzZM;5p?w z|3zDH16o?~pL-55_+>wJ7T}lv{&NAtcr>8oQJ4?_NMbsQ57h+R;27;;bnu%20RIAe C*GxhH literal 0 HcmV?d00001 diff --git a/src/AppInstallerCLIE2ETests/ValidateCommand.cs b/src/AppInstallerCLIE2ETests/ValidateCommand.cs new file mode 100644 index 0000000000..62adedb292 --- /dev/null +++ b/src/AppInstallerCLIE2ETests/ValidateCommand.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace AppInstallerCLIE2ETests +{ + using NUnit.Framework; + + public class ValidateCommand + { + [Test] + public void ValidateCommands() + { + // Validate a good yaml + var result = TestCommon.RunAICLICommand("validate", TestCommon.GetTestDataFile("Manifests\\TestExeInstaller.yaml")); + Assert.AreEqual(result.ExitCode, Constants.ErrorCode.S_OK); + Assert.True(result.StdOut.Contains("Manifest validation succeeded.")); + + // Validate invalid yaml + result = TestCommon.RunAICLICommand("validate", TestCommon.GetTestDataFile("Manifests\\TestInvalidManifest.yaml")); + Assert.AreEqual(result.ExitCode, Constants.ErrorCode.S_OK); + Assert.True(result.StdOut.Contains("Manifest validation failed.")); + + // Input file not found + result = TestCommon.RunAICLICommand("validate", TestCommon.GetTestDataFile("Manifests\\DoesNotExist")); + Assert.AreEqual(result.ExitCode, Constants.ErrorCode.ERROR_FILE_NOT_FOUND); + Assert.True(result.StdOut.Contains("File does not exist")); + } + } +} \ No newline at end of file diff --git a/src/AppInstallerCLIPackage/Package.appxmanifest b/src/AppInstallerCLIPackage/Package.appxmanifest index d93444f605..e581f03b39 100644 --- a/src/AppInstallerCLIPackage/Package.appxmanifest +++ b/src/AppInstallerCLIPackage/Package.appxmanifest @@ -1,13 +1,10 @@  + xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" + xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" + xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5" + xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" + IgnorableNamespaces="uap uap5 rescap"> App Installer CLI @@ -28,7 +25,7 @@ - + diff --git a/src/AppInstallerCLITests/Run-TestsInPackage.ps1 b/src/AppInstallerCLITests/Run-TestsInPackage.ps1 index d0bee149f8..4b9fb243b5 100644 --- a/src/AppInstallerCLITests/Run-TestsInPackage.ps1 +++ b/src/AppInstallerCLITests/Run-TestsInPackage.ps1 @@ -145,4 +145,7 @@ if ($ScriptWait) Wait-ForFileClose $TestResultsTarget } Write-Host "Done" -} + + Write-Host "Remove registered package" + Get-AppxPackage AppInstallerCLI | Remove-AppxPackage +} \ No newline at end of file diff --git a/src/AppInstallerCLITests/Sources.cpp b/src/AppInstallerCLITests/Sources.cpp index 7fcf054349..d16633d647 100644 --- a/src/AppInstallerCLITests/Sources.cpp +++ b/src/AppInstallerCLITests/Sources.cpp @@ -74,7 +74,8 @@ struct TestSource : public ISource static std::shared_ptr Create(const SourceDetails& details) { - return std::make_shared(details); + // using return std::make_shared(details); will crash the x86 test during destruction. + return std::shared_ptr(new TestSource(details)); } // ISource diff --git a/src/AppInstallerCLITests/TEST-AppInstallerCLI-1.xml b/src/AppInstallerCLITests/TEST-AppInstallerCLI-1.xml deleted file mode 100644 index 9064fed508..0000000000 --- a/src/AppInstallerCLITests/TEST-AppInstallerCLI-1.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.vcxproj b/src/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.vcxproj index f7e97981d1..452422ed5d 100644 --- a/src/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.vcxproj +++ b/src/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.vcxproj @@ -5,7 +5,10 @@ {6CB84692-5994-407D-B9BD-9216AF77FE83} Win32Proj AppInstallerTestExeInstaller - 10.0 + 10.0.18362.0 + 10.0.16299.0 + true + true @@ -17,6 +20,14 @@ Release Win32 + + Debug + ARM + + + Release + ARM + Debug x64 @@ -25,6 +36,14 @@ Release x64 + + Debug + ARM64 + + + Release + ARM64 + Application @@ -70,101 +89,64 @@ - - - - - - - - - - + - - false - - - true - - - true - - - false - - + - - - Level3 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp17 + NotUsing + pch.h + $(IntDir)pch.pch + _CONSOLE;%(PreprocessorDefinitions) + Level4 + %(AdditionalOptions) /permissive- /bigobj - - Console - true - true - true - - + - - - Level3 - true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp17 + Disabled + _DEBUG;%(PreprocessorDefinitions) + true + true + true + stdcpp17 + stdcpp17 + stdcpp17 MultiThreadedDebugDLL - true Console - true + false - + - - - Level3 - true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp17 - MultiThreadedDebugDLL - true + WIN32;%(PreprocessorDefinitions) + true + stdcpp17 - - Console - true - - + - - - Level3 + MaxSpeed true true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - stdcpp17 + NDEBUG;%(PreprocessorDefinitions) + true + true + true + true + stdcpp17 + stdcpp17 + stdcpp17 + stdcpp17 Console true true - true + false @@ -174,6 +156,6 @@ - + \ No newline at end of file diff --git a/src/AppInstallerTestExeInstaller/main.cpp b/src/AppInstallerTestExeInstaller/main.cpp index edc1fc9202..e15adc85dd 100644 --- a/src/AppInstallerTestExeInstaller/main.cpp +++ b/src/AppInstallerTestExeInstaller/main.cpp @@ -4,17 +4,30 @@ #include #include #include +#include +// The installer simply prints all args to an output file int main(int argc, const char** argv) { - std::filesystem::path temp = std::filesystem::temp_directory_path(); - temp /= "TestExeInstalled.txt"; - std::ofstream file(temp, std::ofstream::out); + std::filesystem::path outFilePath = std::filesystem::temp_directory_path(); + std::stringstream outContent; for (int i = 1; i < argc; i++) { - file << argv[i] << ' '; + outContent << argv[i] << ' '; + + // Supports custom install path. + if (_stricmp(argv[i], "/InstallDir") == 0 && ++i < argc) + { + outFilePath = argv[i]; + outContent << argv[i] << ' '; + } } + outFilePath /= "TestExeInstalled.txt"; + std::ofstream file(outFilePath, std::ofstream::out); + + file << outContent.str(); + file.close(); } diff --git a/src/AppInstallerTestMsiInstaller/AppInstallerTestMsiInstaller.vdproj b/src/AppInstallerTestMsiInstaller/AppInstallerTestMsiInstaller.vdproj new file mode 100644 index 0000000000..79d046860e --- /dev/null +++ b/src/AppInstallerTestMsiInstaller/AppInstallerTestMsiInstaller.vdproj @@ -0,0 +1,709 @@ +"DeployProject" +{ +"VSVersion" = "3:800" +"ProjectType" = "8:{978C614F-708E-4E1A-B201-565925725DBA}" +"IsWebType" = "8:FALSE" +"ProjectName" = "8:AppInstallerTestMsiInstaller" +"LanguageId" = "3:1033" +"CodePage" = "3:1252" +"UILanguageId" = "3:1033" +"SccProjectName" = "8:" +"SccLocalPath" = "8:" +"SccAuxPath" = "8:" +"SccProvider" = "8:" + "Hierarchy" + { + } + "Configurations" + { + "Debug" + { + "DisplayName" = "8:Debug" + "IsDebugOnly" = "11:TRUE" + "IsReleaseOnly" = "11:FALSE" + "OutputFilename" = "8:Debug\\AppInstallerTestMsiInstaller.msi" + "PackageFilesAs" = "3:2" + "PackageFileSize" = "3:-2147483648" + "CabType" = "3:1" + "Compression" = "3:2" + "SignOutput" = "11:FALSE" + "CertificateFile" = "8:" + "PrivateKeyFile" = "8:" + "TimeStampServer" = "8:" + "InstallerBootstrapper" = "3:2" + "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}" + { + "Enabled" = "11:TRUE" + "PromptEnabled" = "11:TRUE" + "PrerequisitesLocation" = "2:1" + "Url" = "8:" + "ComponentsUrl" = "8:" + "Items" + { + "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:.NETFramework,Version=v4.7.2" + { + "Name" = "8:Microsoft .NET Framework 4.7.2 (x86 and x64)" + "ProductCode" = "8:.NETFramework,Version=v4.7.2" + } + } + } + } + "Release" + { + "DisplayName" = "8:Release" + "IsDebugOnly" = "11:FALSE" + "IsReleaseOnly" = "11:TRUE" + "OutputFilename" = "8:Release\\AppInstallerTestMsiInstaller.msi" + "PackageFilesAs" = "3:2" + "PackageFileSize" = "3:-2147483648" + "CabType" = "3:1" + "Compression" = "3:2" + "SignOutput" = "11:FALSE" + "CertificateFile" = "8:" + "PrivateKeyFile" = "8:" + "TimeStampServer" = "8:" + "InstallerBootstrapper" = "3:2" + "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}" + { + "Enabled" = "11:TRUE" + "PromptEnabled" = "11:TRUE" + "PrerequisitesLocation" = "2:1" + "Url" = "8:" + "ComponentsUrl" = "8:" + "Items" + { + "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:.NETFramework,Version=v4.7.2" + { + "Name" = "8:Microsoft .NET Framework 4.7.2 (x86 and x64)" + "ProductCode" = "8:.NETFramework,Version=v4.7.2" + } + } + } + } + } + "Deployable" + { + "CustomAction" + { + } + "DefaultFeature" + { + "Name" = "8:DefaultFeature" + "Title" = "8:" + "Description" = "8:" + } + "ExternalPersistence" + { + "LaunchCondition" + { + } + } + "File" + { + } + "FileType" + { + } + "Folder" + { + "{3C67513D-01DD-4637-8A68-80971EB9504F}:_3FD954FA64934D1C9D4F66157C4603AF" + { + "DefaultLocation" = "8:[ProgramFilesFolder][Manufacturer]\\[ProductName]" + "Name" = "8:#1925" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:TARGETDIR" + "Folders" + { + } + } + "{1525181F-901A-416C-8A58-119130FE478E}:_7CE3351BC05D486393C4720064B75896" + { + "Name" = "8:#1916" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:DesktopFolder" + "Folders" + { + } + } + "{1525181F-901A-416C-8A58-119130FE478E}:_9537533CAD3E4467B320694E22A39C4C" + { + "Name" = "8:#1919" + "AlwaysCreate" = "11:FALSE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:ProgramMenuFolder" + "Folders" + { + } + } + } + "LaunchCondition" + { + } + "Locator" + { + } + "MsiBootstrapper" + { + "LangId" = "3:1033" + "RequiresElevation" = "11:FALSE" + } + "Product" + { + "Name" = "8:Microsoft Visual Studio" + "ProductName" = "8:AppInstallerTestMsiInstaller" + "ProductCode" = "8:{A5D36CF1-1993-4F63-BFB4-3ACD910D36A1}" + "PackageCode" = "8:{B21B22D8-5E23-401C-84FA-EE074DB23F8F}" + "UpgradeCode" = "8:{B9CF9DD5-D46F-4CE0-BFC9-633BF9D3A6F4}" + "AspNetVersion" = "8:4.0.30319.0" + "RestartWWWService" = "11:FALSE" + "RemovePreviousVersions" = "11:FALSE" + "DetectNewerInstalledVersion" = "11:TRUE" + "InstallAllUsers" = "11:FALSE" + "ProductVersion" = "8:1.0.0" + "Manufacturer" = "8:AppInstallerCLI" + "ARPHELPTELEPHONE" = "8:" + "ARPHELPLINK" = "8:" + "Title" = "8:AppInstallerTestMsiInstaller" + "Subject" = "8:" + "ARPCONTACT" = "8:AppInstallerCLI" + "Keywords" = "8:" + "ARPCOMMENTS" = "8:" + "ARPURLINFOABOUT" = "8:" + "ARPPRODUCTICON" = "8:" + "ARPIconIndex" = "3:0" + "SearchPath" = "8:" + "UseSystemSearchPath" = "11:TRUE" + "TargetPlatform" = "3:0" + "PreBuildEvent" = "8:" + "PostBuildEvent" = "8:" + "RunPostBuildEvent" = "3:0" + } + "Registry" + { + "HKLM" + { + "Keys" + { + "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_951AD5F7C8424CCAB911C2469F382BA0" + { + "Name" = "8:Software" + "Condition" = "8:" + "AlwaysCreate" = "11:FALSE" + "DeleteAtUninstall" = "11:FALSE" + "Transitive" = "11:FALSE" + "Keys" + { + "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_1245A15ED08E4D31AC11FE6C6AF43AA6" + { + "Name" = "8:[Manufacturer]" + "Condition" = "8:" + "AlwaysCreate" = "11:FALSE" + "DeleteAtUninstall" = "11:FALSE" + "Transitive" = "11:FALSE" + "Keys" + { + } + "Values" + { + } + } + } + "Values" + { + } + } + } + } + "HKCU" + { + "Keys" + { + "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_A0E8E016B459429AB33F8A8041B409CF" + { + "Name" = "8:Software" + "Condition" = "8:" + "AlwaysCreate" = "11:FALSE" + "DeleteAtUninstall" = "11:FALSE" + "Transitive" = "11:FALSE" + "Keys" + { + "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_6F792619739B49D49348459164023C26" + { + "Name" = "8:[Manufacturer]" + "Condition" = "8:" + "AlwaysCreate" = "11:FALSE" + "DeleteAtUninstall" = "11:FALSE" + "Transitive" = "11:FALSE" + "Keys" + { + } + "Values" + { + } + } + } + "Values" + { + } + } + } + } + "HKCR" + { + "Keys" + { + } + } + "HKU" + { + "Keys" + { + } + } + "HKPU" + { + "Keys" + { + } + } + } + "Sequences" + { + } + "Shortcut" + { + } + "UserInterface" + { + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_07F5BD380D034D2788D0E26EC943AF9E" + { + "Name" = "8:#1900" + "Sequence" = "3:2" + "Attributes" = "3:1" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_0F2C662EB54446EEBB450AB41783B804" + { + "Sequence" = "3:300" + "DisplayName" = "8:Confirm Installation" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminConfirmDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_5B669F9D2835440A97450ED9A579EBB0" + { + "Sequence" = "3:100" + "DisplayName" = "8:Welcome" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminWelcomeDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "CopyrightWarning" + { + "Name" = "8:CopyrightWarning" + "DisplayName" = "8:#1002" + "Description" = "8:#1102" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:1" + "Value" = "8:#1202" + "DefaultValue" = "8:#1202" + "UsePlugInResources" = "11:TRUE" + } + "Welcome" + { + "Name" = "8:Welcome" + "DisplayName" = "8:#1003" + "Description" = "8:#1103" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:1" + "Value" = "8:#1203" + "DefaultValue" = "8:#1203" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_A1B6CF1DE99744E9BA298D9516F4FBBB" + { + "Sequence" = "3:200" + "DisplayName" = "8:Installation Folder" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminFolderDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_31DFC87DB7EB49BBBE91080D4E17EBC3" + { + "Name" = "8:#1901" + "Sequence" = "3:2" + "Attributes" = "3:2" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_B0FC86DC72004463B28043005E93933D" + { + "Sequence" = "3:100" + "DisplayName" = "8:Progress" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminProgressDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "ShowProgress" + { + "Name" = "8:ShowProgress" + "DisplayName" = "8:#1009" + "Description" = "8:#1109" + "Type" = "3:5" + "ContextData" = "8:1;True=1;False=0" + "Attributes" = "3:0" + "Setting" = "3:0" + "Value" = "3:1" + "DefaultValue" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_49F7C7303D464C18981485552AA18870" + { + "Name" = "8:#1901" + "Sequence" = "3:1" + "Attributes" = "3:2" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_78EF5C34DBDB4BC88F2789CBE1F17043" + { + "Sequence" = "3:100" + "DisplayName" = "8:Progress" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdProgressDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "ShowProgress" + { + "Name" = "8:ShowProgress" + "DisplayName" = "8:#1009" + "Description" = "8:#1109" + "Type" = "3:5" + "ContextData" = "8:1;True=1;False=0" + "Attributes" = "3:0" + "Setting" = "3:0" + "Value" = "3:1" + "DefaultValue" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_68474A3513F54E56B4D451594D7639DC" + { + "Name" = "8:#1902" + "Sequence" = "3:2" + "Attributes" = "3:3" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_3EC2CCC643CA4EEB9DAFF092520273EE" + { + "Sequence" = "3:100" + "DisplayName" = "8:Finished" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminFinishedDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_81A3A282324C416DB8EA6A5FABEAD776" + { + "UseDynamicProperties" = "11:FALSE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdUserInterface.wim" + } + "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_869386ADC36F4DAE92F694770A481917" + { + "UseDynamicProperties" = "11:FALSE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdBasicDialogs.wim" + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_9E39D7A2A2BB4185AE8290AF159CBDE8" + { + "Name" = "8:#1902" + "Sequence" = "3:1" + "Attributes" = "3:3" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_18EEDC13BA92450EA46E5CFAD31164FE" + { + "Sequence" = "3:100" + "DisplayName" = "8:Finished" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdFinishedDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "UpdateText" + { + "Name" = "8:UpdateText" + "DisplayName" = "8:#1058" + "Description" = "8:#1158" + "Type" = "3:15" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:1" + "Value" = "8:#1258" + "DefaultValue" = "8:#1258" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_A1D7AFF21DC048769B063F0ABB6BAD93" + { + "Name" = "8:#1900" + "Sequence" = "3:1" + "Attributes" = "3:1" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_6AFCB2A470844F02AC97138D2C4255B5" + { + "Sequence" = "3:300" + "DisplayName" = "8:Confirm Installation" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdConfirmDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_73B000DF31AF44D789DC52D2EB3AC63B" + { + "Sequence" = "3:200" + "DisplayName" = "8:Installation Folder" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdFolderDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "InstallAllUsersVisible" + { + "Name" = "8:InstallAllUsersVisible" + "DisplayName" = "8:#1059" + "Description" = "8:#1159" + "Type" = "3:5" + "ContextData" = "8:1;True=1;False=0" + "Attributes" = "3:0" + "Setting" = "3:0" + "Value" = "3:1" + "DefaultValue" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_E411887483814552AF4BF33BBB4F1B1D" + { + "Sequence" = "3:100" + "DisplayName" = "8:Welcome" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdWelcomeDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "CopyrightWarning" + { + "Name" = "8:CopyrightWarning" + "DisplayName" = "8:#1002" + "Description" = "8:#1102" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:1" + "Value" = "8:#1202" + "DefaultValue" = "8:#1202" + "UsePlugInResources" = "11:TRUE" + } + "Welcome" + { + "Name" = "8:Welcome" + "DisplayName" = "8:#1003" + "Description" = "8:#1103" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:1" + "Value" = "8:#1203" + "DefaultValue" = "8:#1203" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + } + "MergeModule" + { + } + "ProjectOutput" + { + "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_9892A03006D742BB8C58FDF406605C8B" + { + "SourcePath" = "8:..\\x86\\Release\\AppInstallerTestExeInstaller\\AppInstallerTestExeInstaller.exe" + "TargetName" = "8:" + "Tag" = "8:" + "Folder" = "8:_3FD954FA64934D1C9D4F66157C4603AF" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + "ProjectOutputGroupRegister" = "3:1" + "OutputConfiguration" = "8:Release|Win32" + "OutputGroupCanonicalName" = "8:Built" + "OutputProjectGuid" = "8:{6CB84692-5994-407D-B9BD-9216AF77FE83}" + "ShowKeyOutput" = "11:TRUE" + "ExcludeFilters" + { + } + } + } + } +} diff --git a/src/AppInstallerTestMsixInstaller/AppInstallerTestMsixInstaller.wapproj b/src/AppInstallerTestMsixInstaller/AppInstallerTestMsixInstaller.wapproj new file mode 100644 index 0000000000..c17714a2ae --- /dev/null +++ b/src/AppInstallerTestMsixInstaller/AppInstallerTestMsixInstaller.wapproj @@ -0,0 +1,78 @@ + + + + 15.0 + + + + Debug + x86 + + + Release + x86 + + + Debug + x64 + + + Release + x64 + + + Debug + ARM + + + Release + ARM + + + Debug + ARM64 + + + Release + ARM64 + + + Debug + AnyCPU + + + Release + AnyCPU + + + + $(MSBuildExtensionsPath)\Microsoft\DesktopBridge\ + + + + 3e2cba31-ceba-4d63-bf52-49c0718e19ea + 10.0.18362.0 + 10.0.16299.0 + en-US + false + ..\AppInstallerTestExeInstaller\AppInstallerTestExeInstaller.vcxproj + + + + Designer + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AppInstallerTestMsixInstaller/Images/LockScreenLogo.scale-200.png b/src/AppInstallerTestMsixInstaller/Images/LockScreenLogo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..735f57adb5dfc01886d137b4e493d7e97cf13af3 GIT binary patch literal 1430 zcmaJ>TTC2P7~aKltDttVHYH6u8Io4i*}3fO&d$gd*bA_<3j~&e7%8(eXJLfhS!M@! zKrliY>>6yT4+Kr95$!DoD(Qn-5TP|{V_KS`k~E6(LGS@#`v$hQo&^^BKsw3HIsZBT z_y6C2n`lK@apunKojRQ^(_P}Mgewt$(^BBKCTZ;*xa?J3wQ7~@S0lUvbcLeq1Bg4o zH-bvQi|wt~L7q$~a-gDFP!{&TQfc3fX*6=uHv* zT&1&U(-)L%Xp^djI2?~eBF2cxC@YOP$+9d?P&h?lPy-9M2UT9fg5jKm1t$m#iWE{M zIf%q9@;fyT?0UP>tcw-bLkz;s2LlKl2qeP0w zECS7Ate+Awk|KQ+DOk;fl}Xsy4o^CY=pwq%QAAKKl628_yNPsK>?A>%D8fQG6IgdJ ztnxttBz#NI_a@fk7SU`WtrpsfZsNs9^0(2a z@C3#YO3>k~w7?2hipBf{#b6`}Xw1hlG$yi?;1dDs7k~xDAw@jiI*+tc;t2Lflg&bM)0!Y;0_@=w%`LW^8DsYpS#-bLOklX9r?Ei}TScw|4DbpW%+7 zFgAI)f51s}{y-eWb|vrU-Ya!GuYKP)J7z#*V_k^Xo>4!1Yqj*m)x&0L^tg3GJbVAJ zJ-Pl$R=NAabouV=^z_t;^K*0AvFs!vYU>_<|I^#c?>>CR<(T?=%{;U=aI*SbZADLH z&(f2wz_Y0??Tf|g;?|1Znw6}6U43Q#qNRwv1vp9uFn1)V#*4p&%$mP9x&15^OaBiDS(XppT|z^>;B{PLVEbS3IFYV yGvCsSX*m literal 0 HcmV?d00001 diff --git a/src/AppInstallerTestMsixInstaller/Images/SplashScreen.scale-200.png b/src/AppInstallerTestMsixInstaller/Images/SplashScreen.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..023e7f1feda78d5100569825acedfd213a0d84e9 GIT binary patch literal 7700 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 literal 0 HcmV?d00001 diff --git a/src/AppInstallerTestMsixInstaller/Images/Square150x150Logo.scale-200.png b/src/AppInstallerTestMsixInstaller/Images/Square150x150Logo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..af49fec1a5484db1d52a7f9b5ec90a27c7030186 GIT binary patch literal 2937 zcma)84OCO-8BSud5)jwMLRVKgX(S?$n?Ld|vrsm<$CF7)&zTbyy1FE5bU`Q17MRv`9ue$;R(@8kR;#vJ*IM0>cJIAOte!d7oRgdH zd%ySjdB6L9=gX^A6)VzH7p2l@v~3zJAMw|DFy#^)F@@F*`mqUn=Il>l)8_+ab;nOW{%+iPx z+s{Eu|&pIs)Z7{La9~?xKfyl z#43?gjEL15d4WbOZo#SiP%>DB^+BcnJ=7dHEe;r#G=tuw|ka z%q@}##Uh7;tc%L_64m(kHtw74ty%BJMb)_1)#S0j`)F8_1jF7vScpsnH=0V19bO8y zR`0SjIdCUo&=>JwMQF8KHA<{ODHTiQh}0^@5QRmCA?gOH6_H3K^-_sNB^RrdNuK-R zOO*vOrKCVvDwgUck`kF(E7j{I#iiN;b*ZdCt4m@HPA`EuEqGGf4%!K<;(=I=&Vyrw z%TwcWtxa}8mCZ%Cyf&ActJ6_$ox5z6-D!0-dvnRx6t7y3d+h6QYpKWO;8OdnvERo7 zuEf>ih5`wqY)~o@OeVt-wM?Q!>QzdGRj!bz6fzYrfw$hZfAKzr2-M+D+R>}~oT574c;_3zquHcElqKIsryILt3g8n3jcMb+j?i?-L3FpZJ z2WRVBRdDPc+G5aaYg#5hpE+6nQ|(VSoxT3|biF;BUq#==-27Xi=gihDPYP$7?=9cP zYKE$jeQ|3~_L0VG-(F~2ZPyD0=k{J4Q~h(t__{-mz_w8{JDY9{`1ouzz!Vr5!ECdE z6U~O1k8c}24V7~zzXWTV-Pe4)y}wQJS&q%H5`Fo_f_JvIU489aCX$;P`u#!I-=^4ijC2{&9!O&h>mi?9oYD=GC#%)6{GzN6nQYw+Fal50!#x^asjBBR50i`+mho*ttoqV)ubM2KD9S~k7+FR4>{29?6 z{!l6kDdyTN0YJ9LgkPWeXm|gyi@zM3?0@{&pXT12w|78&W-q!RRF)&iLCEZVH<|fR zN0fr2^t8H(>L?>K#>^+jWROLral(Qy-xoBq1U7A&DV||wClb)Otd9?(gZ|8znMF}D zf<1haWz^s0qgecz;RFGt0C-B4g`jNGHsFU+;{<%t65v^sjk^h$lmWn#B0#_)9ij&d z-~lc`A)YYExi^7sBuPM^Y|wA2g*5?`K?#7tzELQYNxGo$UB$4J8RJp1k(8Jj+~hMT zlN~>M@KTTh^--8y3PK_NZ@AC!{PT=CziBzGd+wTJ^@icH!Bd}%)g8V)%K?|c&WTUk zy}qv1C%(fjRoZ4ozC3{O%@5?)XzH35zHns$pgU*Q?fj4v?fp1Qbm+j;3l;9jam9Da zXVcKjPlQ73x78QPu|Ffm6x?`~e3oD=gl=4kYK?={kD5j~QCXU)`HSdduNNENzA*2$ zOm3PzF!lN5e*06-f1Uot67wY#{o-S1!KZ7E=!~7ynnk9_iJR#kFoNbAOT#^2Gd17F zMmvU6>lndZQGd|ax9kUoXXO+$N?|j@6qpsF&_j7YXvwo_C{JpmLw5&#e6k>atv%es z5)7r*Wvv_JkUpT}M!_o!nVlEk1Zbl=a*2hQ*<|%*K1Glj^FcF`6kTzGQ3lz~2tCc@ z&x|tj;aH&1&9HwcJBcT`;{?a+pnej;M1HO(6Z{#J!cZA04hnFl;NXA+&`=7bjW_^o zfC40u3LMG?NdPtwGl>Tq6u}*QG)}-y;)lu-_>ee3kibW(69n0$0Zy!}9rQz%*v1iO zT9_H>99yIrSPYVy6^);rR}7Yo=J_T@hi+qhTZXnVWyf;JDYm5#eYLTxr*?kiNn!+Y zQ+LUkBafNJ#rH#C(?d5^;gw9o#%daEI{mA*LHPIHPU`#|H$hD zwm>0&+kahQ)E#%~k>&5@&#Vg82H?s%71=)(soi@174pi9--2{w{1$}Sz4zGn3Du&x bht0Iza^2ykEt4(epJ78uh5nDlX8(TxzDYwP literal 0 HcmV?d00001 diff --git a/src/AppInstallerTestMsixInstaller/Images/Square44x44Logo.scale-200.png b/src/AppInstallerTestMsixInstaller/Images/Square44x44Logo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..ce342a2ec8a61291ba76c54604aea7e9d20af11b GIT binary patch literal 1647 zcmaJ?eM}Q)7(e+G1Q(|`V9JhTI2>MkceK4;p;PR&$Pi?ejk3YQ_3o`S&|W_dsOZ8# zWPTt69g`t$ab`0cj-Y0yiBSOqmd)tG7G(}M5aP0_%&9TijB#&)I{zSE^4@#z^FF`l z`8{8`o%wlL(UI|y2!cdsuVamHH~H86F!*-15em4)NqUpCQM5?aoC_eCf@lV4wvF2a zjDQn1JBL69f&@2M3rvzJcfE!eZ8FZUBlFlC5RD)it33{mF9#B82AiyQE%w)`vlwa> zv{<1sm&kSKK$&%2jSFn7$t&P%%6Ue>R=EAnG8N7fqynWG8L3p!4801a;8{+nliO(qd(jNJ_?+9W3#hLIDLoT6~3fx9=`CC-D}-AMrpEO7HK zt3$GicGPc?GmDjy7K2P@La;eu4!$zWCZ`ym{Z$b zu-O6RM&K4JT|BIZB`E-gxqG%FzanI#+2FFmqHqXG7yxWB=w55RGOM)$xMb(>kSNR z2w=1AZi%z=AmG~yea~XaXJR!v7vLn(RUnELfiB1|6D84ICOS}^Zo2AdN}<&*h}G_u z{xZ!(%>tLT3J3<5XhWy-tg+6)0nmUUENLW8TWA{R6bgVd3X;anYFZ^IRis*_P-C-r z;i>%1^eL3UI2-{w8nuFFcs0e~7J{O2k^~Ce%+Ly4U?|=!0LH=t6()xi<^I-rs+9sF z*q{E-CxZbGPeu#a;XJwE;9S1?#R&uns>^0G3p`hEUF*v`M?@h%T%J%RChmD|EVydq zmHWh*_=S%emRC*mhxaVLzT@>Z2SX0u9v*DIJ@WC^kLVdlGV6LpK$KIrlJqc zpJ921)+3JJdTx|<`G&kXpKkjGJv=76R`yYIQ{#c-`%+`#V(7}Q;&@6U8!Td1`d;?N z_9mnI#?AA}4J!r)LN4!E-@H5eXauuB7TOawS>Y|{-P?NNx-lq+z1W-+y(;39P&&LP zL{N80?&=C*qKmdA^moMZRuPcD!B<*mq$ch=0Cnlitw#txRWhb3%TQvPqjkC`F69G4b! ze7z9MZ#+;_#l?H37UqUhDFb^l&s2{oM$3I0o^Q!yx;;V)QmCMo)Tb_ui|mit8MS?U zm##6$sZZ1$@|s%?l@>4Z<*Q}sRBSKMhb4I{e5LdEhsHIHTe8Bod5c>6QtT>$XgUBz z6MK`kO$=jmt@FqggOhJ5j~e@ygRbG;<{Vu)*+nn9aQeo0;$#j;|MS=S$&L?BeV25z xs3B`@=#`5TF{^6(A1rvdY@|-RtQ|iS5{tyX+wH?;n8E)G$kykv-D^wh{{!TZT%7;_ literal 0 HcmV?d00001 diff --git a/src/AppInstallerTestMsixInstaller/Images/Square44x44Logo.targetsize-24_altform-unplated.png b/src/AppInstallerTestMsixInstaller/Images/Square44x44Logo.targetsize-24_altform-unplated.png new file mode 100644 index 0000000000000000000000000000000000000000..f6c02ce97e0a802b85f6021e822c89f8bf57d5cd GIT binary patch literal 1255 zcmaJ>TWs4@7*5+{G#S+&C!qC#> zf>5N3P6jO*Cz>ug*(_DmW=)kea&m$gZ^+nyiF`;j%w@}y8)>p*SH}C`m?DXeieF2U zyQHecc_L%Gh!7GMt+hG06y;+|p4>m~}PjA}rKViGiEnn7G0ZO<>G|7q;2?NwGCM3s?eued6%hd$B+ z*kQJ{#~$S=DFE(%=E+UkmlEI*%3llUf~8Ja9YU1Vui0IbGBkW_gHB%Rd&!!ioX zs40O?i9I{};kle7GMvE7(rk`la=gTI)47=>%?q@^iL-nUo3}h4S}N-KHn8t5mVP8w z&bSErwp+37 zNJJ8?a|{r5Q3R0Z5s-LB1WHOwYC@7pCHWND#cL1cZ?{kJ368_*(UDWUDyb<}0y@o# zfMF016iMWPCb6obAxT$JlB6(2DrlXDTB&!0`!m??4F(qWMhjVZo?JXQmz`1*58Z=& zcDmB|S-E@j?BoFGix0flckqdS4jsPNzhfWyWIM98GxcLs89C(~dw%$_t;JjX-SD}E zfiGV;{8Q%8r}w9x>EEigW81>`kvnU@pK)4+xk9@+bNj9L!AAZ@SZ@q|)&BmY3+HZx zul~BeG4|}-;L%cHViQGQX?^zFfO0&#cHwel=d`lH9sJ-@Sl@n*(8J2>%Ac`IxyY?Q z{=GhWvC#gu-~Ia7*n{=+;qM?Ul_wy1+u7ho;=`>EwP^g~R@{unBds`!#@}tluZQpS zm)M~nYEifJWJGx?_6DcTy>#uh%>!H9=hb^(v`=m3F1{L>db=<5_tm+_&knAQ2EU$s Mu9UqpbNZeC0BbUo^Z)<= literal 0 HcmV?d00001 diff --git a/src/AppInstallerTestMsixInstaller/Images/StoreLogo.png b/src/AppInstallerTestMsixInstaller/Images/StoreLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..7385b56c0e4d3c6b0efe3324aa1194157d837826 GIT binary patch literal 1451 zcmaJ>eN5D57_Z|bH;{0+1#mbl)eTU3{h)Wf7EZV?;HD@XL@{B`Ui%(2aMxQ~xdXSv z5nzWi(LW)U2=Vc-cY@s7nPt{i0hc6!7xN4NNHI#EQl>YNBy8l4%x9gr_W-j zEZMQmmTIy(>;lblRfh`dIyTgc9W5d!VP$L4(kKrN1c5G~(O_#xG zAJCNTstD^5SeXFB+&$h=ToJP2H>xr$iqPs-#O*;4(!Fjw25-!gEb*)mU}=)J;Iu>w zxK(5XoD0wrPSKQ~rbL^Cw6O_03*l*}i=ydbu7adJ6y;%@tjFeXIXT+ms30pmbOP%Q zX}S;+LBh8Tea~TSkHzvX6$rYb)+n&{kSbIqh|c7hmlxmwSiq5iVhU#iEQ<>a18|O^Sln-8t&+t`*{qBWo5M?wFM(JuimAOb5!K#D}XbslM@#1ZVz_;!9U zpfEpLAOz=0g@bd6Xj_ILi-x^!M}73h^o@}hM$1jflTs|Yuj9AL@A3<-?MV4!^4q`e z)fO@A;{9K^?W?DbnesnPr6kK>$zaKo&;FhFd(GYFCIU^T+OIMb%Tqo+P%oq(IdX7S zf6+HLO?7o0m+p>~Tp5UrXWh!UH!wZ5kv!E`_w)PTpI(#Iw{AS`gH4^b(bm^ZCq^FZ zY9DD7bH}rq9mg88+KgA$Zp!iWncuU2n1AuIa@=sWvUR-s`Qb{R*kk(SPU^`$6BXz8 zn#7yaFOIK%qGxyi`dYtm#&qqox0$h=pNi#u=M8zUG@bpiZ=3sT=1}Trr}39cC)H|v zbL?W)=&s4zrh)7>L(|cc%$1#!zfL?HjpeP%T+x_a+jZ16b^iKOHxFEX$7d|8${H-* zIrOJ5w&i$>*D>AKaIoYg`;{L@jM((Kt?$N$5OnuPqVvq**Nm}(f0wwOF%iX_Pba;V z;m@wxX&NcV3?<1+u?A{y_DIj7#m3Af1rCE)o`D&Y3}0%7E;iX1yMDiS)sh0wKi!36 zL!Wmq?P^Ku&rK~HJd97KkLTRl>ScGFYZNlYytWnhmuu|)L&ND8_PmkayQb{HOY640 bno1(wj@u8DCVuFR|31B*4ek@pZJqxCDDe1x literal 0 HcmV?d00001 diff --git a/src/AppInstallerTestMsixInstaller/Images/Wide310x150Logo.scale-200.png b/src/AppInstallerTestMsixInstaller/Images/Wide310x150Logo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..288995b397fdbef1fb7e85afd71445d5de1952c5 GIT binary patch literal 3204 zcmbVPeQXow8NYmBd90>}0NP?GhXW~VaeThm=a0tV#EwJMI!)6M3}|c4_Bl3=Kd>G0 z(GHx1wl<7(tP?FsOQkTilSo*iIvF%uArExJ73~P zSv1xEy!U(Wd4A9D`FQV@W3@F^qJ@PEF$@z`Z!*BbFsS(^?B zyiAzJ+q})bkgiQHWqEb*jJD-coHYr1^iocg)l!Qa{Xqs-l~6J}p-|##ZHYofskQ3$ zI0;xzXyhazBeXhIsg5A=%ufo@f)1yy&ScKS0;HF^!r_2UE^lpZEom(+@duma3awTv zCrCL-%D_SvYWIcdHkmI}#50(fkUi)Qgx!80ju>g1za^}ff>JI8Z@^-iCiaCgg@TgF z+vtE?Q9{VQUX&MW9SYYmGcxA14%N2@7FwBTD4N<(2{nWgV8$e3?-F=L^&FrtWn~(U_Q~~^uYiyeY6-KoTnfh9AWz@ zIKje0)u!_Lw)E}G!#kEfwKVdNt(UAf9*f>tEL_(=xco-T%jTi@7YlC3hs2ik%Le0H ztj}RTeCF(5mwvi3_56>-yB?l;J>-1%!9~=fs|QcNG3J~a@JCu`4SB460s0ZO+##4fFUSGLcj_ja^fL4&BKALfb#$6$O?>P@qx2Agl^x0i&ugt zsy5Pyu=()`7HRMG3IB7F1@`_ z+-!J%#i6e^U$e#+C%Q>_qVRzWRsG^W_n+@OcX@vzI&z;mzHNb!GQ?LWA(wtpqHqTM z1OFw_{Zn?fD)p)`c`kOgv{de=v@suGRqY{N^U7gI1VF3*F=obwaXI6ob5__Yn zVTguS!%(NI09J8x#AO_aW!9W7k*UvB;IWDFC3srwftr{kHj%g)fvnAm;&h_dnl~

MY- zf+K}sCe8qU6Ujs`3ua{U0Of$R_gVQBuUA za0v=mu#vIOqiiAZOr&h*$WyOw&k-xr$;G4Ixa!#TJNr>95(h>l%)PUy4p+^SgR(uR zta%k*?ny-+nAr8spEk1fo{J4i!b^Fia`N{_F6@zidA2ZTTrjl#^5Z-2KfB@Cu}l9s z(*|Z2jc?p~vn2f)3y9i*7zJV1L{$?|&q)4oaT;uXi6>1GkRXVTOzAz(RHEmr=eFIi z`}<>-Q?K0GN8!IYxeP1XKXO+jsJbp~o^);Bc;%b7Flpe7;1`Ny@3r7ZR;?R)aJt8C ziNlEC<@3f_lIV4TwV}&e;D!Ee5_|e#g0LUh=5vmYWYm7&2h*M>QPKvGh9-)wfMMW3 z8J9b%1k7dzPzO0_NGQy92BZ^FR6R~6;^6?lqO;-QUP4BY%cG%3vEhbm#>4vIhPBh3 z-+pZGjh$x%Hp{?=FHsMp0&wNPlj00us{&`1ZOZTqs8%4X&xH=UDr*xyBW(Zp&Em94 zf)ZSfn#yg0N)>!1kWdkqJ^S*z0FF5|fj&qcE#Na|%OY0$uO>!&hP+1ywfD_WXk@4J(?MBftK7>$Nvqh@tDuarN%PrTLQ2Uzysx>UV=V zk^RrDSvdQ?0;=hY67EgII-f4`t=+i*yS=Y~!XlqIy_4x&%+OdfbKOFPXS2X5%4R{N z$SQMX^AK6(fA + + + + + + + AppInstallerTestMsixInstaller + AppInstallerTest + Images\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/IndexCreationTool/AppInstallerSQLiteIndexUtilWrapper.cs b/src/IndexCreationTool/AppInstallerSQLiteIndexUtilWrapper.cs new file mode 100644 index 0000000000..10ec22a2d7 --- /dev/null +++ b/src/IndexCreationTool/AppInstallerSQLiteIndexUtilWrapper.cs @@ -0,0 +1,265 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace IndexCreationTool +{ + using System; + using System.IO; + using System.Runtime.InteropServices; + + ///

+ /// Wrapper class around AppInstallerSQLiteIndexUtil index modifier native implementation. + /// + internal class AppInstallerSQLiteIndexUtilWrapper : IDisposable + { + /// + /// Dll name. + /// + public const string DllName = @"AppInstallerSQLiteIndexUtil.dll"; + + private const uint LatestVersion = unchecked((uint)-1); + + private IntPtr indexHandle; + + /// + /// Initializes a new instance of the class. + /// + /// Handle of the index. + private AppInstallerSQLiteIndexUtilWrapper(IntPtr indexHandle) + { + this.indexHandle = indexHandle; + } + + /// + /// Creates a new index file in the specified path. + /// + /// Index file to create. + /// Instance of AppInstallerSQLiteIndexUtilWrapper. + public static AppInstallerSQLiteIndexUtilWrapper Create(string indexFile) + { + try + { + AppInstallerSQLiteIndexCreate( + indexFile, + AppInstallerSQLiteIndexUtilWrapper.LatestVersion, + AppInstallerSQLiteIndexUtilWrapper.LatestVersion, + out IntPtr index); + return new AppInstallerSQLiteIndexUtilWrapper(index); + } + catch (Exception e) + { + Console.WriteLine($"Error to create {indexFile}. {Environment.NewLine}{e.ToString()}"); + throw; + } + } + + /// + /// Open the index. + /// + /// Index file to open. + /// Instance of AppInstallerSQLiteIndexUtilWrapper. + public static AppInstallerSQLiteIndexUtilWrapper Open(string indexFile) + { + try + { + AppInstallerSQLiteIndexOpen(indexFile, out IntPtr index); + return new AppInstallerSQLiteIndexUtilWrapper(index); + } + catch (Exception e) + { + Console.WriteLine($"Error to open {indexFile}. {Environment.NewLine}{e.ToString()}"); + throw; + } + } + + /// + /// Adds manifest to index. + /// + /// Manifest to add. + /// Path of the manifest in the repository. + public void AddManifest(string manifestPath, string relativePath) + { + try + { + Console.WriteLine($"Adding manifest {manifestPath} on index file."); + AppInstallerSQLiteIndexAddManifest(this.indexHandle, manifestPath, relativePath); + return; + } + catch (Exception e) + { + Console.WriteLine($"Error to add manifest {manifestPath} with relative path {relativePath}. {Environment.NewLine}{e.ToString()}"); + throw; + } + } + + /// + /// Updates manifest in the index. + /// + /// Path to manifest to modify. + /// Path of the manifest in the repository. + /// True if index was modified. + public bool UpdateManifest(string manifestPath, string relativePath) + { + try + { + Console.WriteLine($"Updating manifest {manifestPath} on index file."); + + // For now, modifying a manifest implies that the file didn't got moved in the repository. So only + // contents of the file are modified. However, in the future we might support moving which requires + // oldManifestPath, oldRelativePath, newManigestPath and oldManifestPath. + AppInstallerSQLiteIndexUpdateManifest( + this.indexHandle, + manifestPath, + relativePath, + out bool indexModified); + + if (!indexModified) + { + // This means that some of the attributes that don't get indexed, like Description, where + // were modified, so the index doesn't got updated. + Console.WriteLine($"Manifest {manifestPath} didn't result in a modification to the index."); + } + + return indexModified; + } + catch (Exception e) + { + Console.WriteLine($"Error to update manifest {manifestPath} with relative path {relativePath}. {Environment.NewLine}{e.ToString()}"); + throw; + } +} + + /// + /// Delete manifest from index. + /// + /// Path to manifest to modify. + /// Path of the manifest in the repository. + public void RemoveManifest(string manifestPath, string relativePath) + { + try + { + AppInstallerSQLiteIndexRemoveManifest(this.indexHandle, manifestPath, relativePath); + return; + } + catch (Exception e) + { + Console.WriteLine($"Error to remove manifest {manifestPath} with relative path {relativePath}. {Environment.NewLine}{e.ToString()}"); + throw; + } + } + + /// + /// Wrapper for AppInstallerSQLiteIndexPrepareForPackaging. + /// + public void PrepareForPackaging() + { + try + { + AppInstallerSQLiteIndexPrepareForPackaging(this.indexHandle); + return; + } + catch (Exception e) + { + Console.WriteLine($"Error to prepare for packaging. {Environment.NewLine}{e.ToString()}"); + throw; + } + } + + /// + /// Dispose method. + /// + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Dispose method to dispose the Git desktop process runner. + /// + /// Bool value indicating if Dispose is being run. + protected void Dispose(bool disposing) + { + if (disposing) + { + if (this.indexHandle != null) + { + AppInstallerSQLiteIndexClose(this.indexHandle); + } + } + } + + /// + /// Creates a new index file at filePath with the given version. + /// + /// File path to create index. + /// Major version. + /// Minor version. + /// Out handle of the index. + /// HRESULT. + [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr AppInstallerSQLiteIndexCreate(string filePath, uint majorVersion, uint minorVersion, out IntPtr index); + + /// + /// Opens an existing index at filePath. + /// + /// File path of index. + /// Out handle of the index. + /// HRESULT. + [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr AppInstallerSQLiteIndexOpen(string filePath, out IntPtr index); + + /// + /// Closes the index. + /// + /// Handle of the index. + /// HRESULT. + [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr AppInstallerSQLiteIndexClose(IntPtr index); + + /// + /// Adds the manifest at the repository relative path to the index. + /// If the function succeeds, the manifest has been added. + /// + /// Handle of the index. + /// Manifest to add. + /// Path of the manifest in the container. + /// HRESULT. + [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr AppInstallerSQLiteIndexAddManifest(IntPtr index, string manifestPath, string relativePath); + + /// + /// Updates the manifest at the repository relative path in the index. + /// The out value indicates whether the index was modified by the function. + /// + /// Handle of the index. + /// Old manifest path. + /// Old relative path in the container. + /// Out bool if the index is modified. + /// HRESULT. + [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr AppInstallerSQLiteIndexUpdateManifest( + IntPtr index, + string manifestPath, + string relativePath, + [MarshalAs(UnmanagedType.U1)] out bool indexModified); + + /// + /// Removes the manifest at the repository relative path from the index. + /// + /// Index handle. + /// Manifest path to remove. + /// Relative path in the container. + /// HRESULT. + [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr AppInstallerSQLiteIndexRemoveManifest(IntPtr index, string manifestPath, string relativePath); + + /// + /// Removes data that is no longer needed for an index that is to be published. + /// + /// Index handle. + /// HRESULT. + [DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, PreserveSig = false)] + private static extern IntPtr AppInstallerSQLiteIndexPrepareForPackaging(IntPtr index); + } +} diff --git a/src/IndexCreationTool/IndexCreationTool.csproj b/src/IndexCreationTool/IndexCreationTool.csproj new file mode 100644 index 0000000000..8f292319c0 --- /dev/null +++ b/src/IndexCreationTool/IndexCreationTool.csproj @@ -0,0 +1,9 @@ + + + + Exe + netcoreapp3.1 + $(SolutionDir)$(Platform)\$(Configuration)\IndexCreationTool\ + + + diff --git a/src/IndexCreationTool/Program.cs b/src/IndexCreationTool/Program.cs new file mode 100644 index 0000000000..5c0bbf3d97 --- /dev/null +++ b/src/IndexCreationTool/Program.cs @@ -0,0 +1,92 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace IndexCreationTool +{ + using System; + using System.Diagnostics; + using System.IO; + + class Program + { + public const string IndexName = @"index.db"; + public const string IndexPackageName = @"index.msix"; + + static void Main(string[] args) + { + string rootDir = string.Empty; + string appxManifestPath = string.Empty; + string certPath = string.Empty; + + for (int i = 0; i < args.Length; i++) + { + if (args[i] == "-d" && ++i < args.Length) + { + rootDir = args[i]; + } + else if (args[i] == "-m" && ++i < args.Length) + { + appxManifestPath = args[i]; + } + else if (args[i] == "-c" && ++i < args.Length) + { + certPath = args[i]; + } + } + + if (string.IsNullOrEmpty(rootDir)) + { + Console.WriteLine("Usage: IndexCreationTool.exe -d [-m [-c ]]"); + return; + } + + try + { + if (File.Exists(IndexName)) + { + File.Delete(IndexName); + } + + using (var indexHelper = AppInstallerSQLiteIndexUtilWrapper.Create(IndexName)) + { + foreach (string file in Directory.EnumerateFiles(rootDir, "*.yaml", SearchOption.AllDirectories)) + { + indexHelper.AddManifest(file, Path.GetRelativePath(rootDir, file)); + } + indexHelper.PrepareForPackaging(); + } + + if (!string.IsNullOrEmpty(appxManifestPath)) + { + using (StreamWriter outputFile = new StreamWriter("MappingFile.txt")) + { + outputFile.WriteLine("[Files]"); + outputFile.WriteLine($"\"{IndexName}\" \"{IndexName}\""); + outputFile.WriteLine($"\"{appxManifestPath}\" \"AppxManifest.xml\""); + } + + RunCommand("makeappx.exe", $"pack /f MappingFile.txt /o /nv /p {IndexPackageName}"); + + if (!string.IsNullOrEmpty(certPath)) + { + RunCommand("signtool.exe", $"sign /a /fd sha256 /f {certPath} {IndexPackageName}"); + } + } + } + catch (Exception e) + { + Console.WriteLine("Failed. Reason: " + e.Message); + } + + Environment.Exit(0); + } + + static void RunCommand(string command, string args) + { + Process p = new Process(); + p.StartInfo = new ProcessStartInfo(command, args); + p.Start(); + p.WaitForExit(); + } + } +}