winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

README.md (10278B)


      1 # How to Run End-To-End Tests for Windows Package Manager Client
      2 
      3 Most of the tests require having the local test source added into winget. The local test source must be hosted in a localhost web server.
      4 
      5 ## Run locally
      6 The E2E tests are built on the nunit testing framework and can be configured with a Test.runsettings file. The project has its own default parameters but typically you will want to expand it by modifying **src\AppInstallerCLIE2ETests\Test.runsettings** with the parameters that you want and set it up by opening **Test Explorer - Settings - Configure Run Settings point to file: src\AppInstallerCLIE2ETests\Test.runsettings**
      7 
      8 If your tests uses the test source see the [LocalhostWebServer](#LocalhostWebServer) and [WinGetSourceCreator](#WinGetSourceCreator) sections.
      9 
     10 ### Run settings.
     11 |Parameter| Description  |
     12 |--|--|
     13 | PackagedContext | Indicates if the test should be run under packaged context |
     14 | VerboseLogging | Turn on/off verbose logging in the test result |
     15 | AICLIPath | The AICLI executable under test. If using loose file registration and using Invoke-Command when         AppExecutionAlias is not available, this will be relative path to package root. |
     16 | AICLIPackagePath | Used in packaged context. Path to the package containing executable under test. If LooseFileRegistration is true, this should be path to unpackaged root. |
     17 | LooseFileRegistration | Bool to set if loose file registration should be used. |
     18 | InvokeCommandInDesktopPackage | Bool to indicate using Invoke-CommandInDesktopPackage for test execution. This is used when AppExecutionAlias is not available, or disabled. |
     19 | StaticFileRootPath | Path to the set of static test files that will be served as the source for testing purposes. This path should be identical to the one provided to the LocalHostWebServer|
     20 | MsixTestInstallerPath | The MSIX (or APPX) Installer executable under test. |
     21 | ExeTestInstallerPath |The Exe Installer executable under test. |
     22 | MsiTestInstallerPath | The MSI Installer executable under test. |
     23 | PackageCertificatePath | Signing Certificate Path used to certify test index source package |
     24 | PowerShellModulePath | Path to the PowerShell module manifest file under test |
     25 | PowerShellModulePath | The local server cert file |
     26 | SkipTestSource | I solemnly swear the test won't use the local test source or the source is already set up. |
     27 
     28 #### Example of Test.runsettings with completed parameters:
     29 Assuming you clone winget-cli in c:\dev, the localhost web server is running in c:\dev\TestLocalIndex (without creating the test source) and you built x64 Debug, this should cover most of the tests.
     30 
     31     <RunSettings>
     32         <TestRunParameters>
     33             <Parameter name="PackagedContext" value="false" />
     34             <Parameter name="VerboseLogging" value="true" />
     35             <Parameter name="AICLIPath" value="c:\dev\winget-cli\src\AppInstallerCLIPackage\bin\x64\Debug\AppInstallerCLI\winget.exe" />
     36             <Parameter name="InvokeCommandInDesktopPackage" value="false" />
     37             <Parameter name="StaticFileRootPath" value="c:\dev\TestLocalIndex" />
     38             <Parameter name="MsixTestInstallerPath" value="C:\dev\Temp\AppInstallerTestMsixInstaller.msix" />
     39             <Parameter name="ExeTestInstallerPath" value="c:\dev\winget-cli\src\x64\Debug\AppInstallerTestExeInstaller\AppInstallerTestExeInstaller.exe" />
     40             <Parameter name="MsiTestInstallerPath" value="c:\dev\winget-cli\src\AppInstallerCLIE2ETests\TestData\AppInstallerTestMsiInstaller.msi" />
     41             <Parameter name="PackageCertificatePath" value="C:\dev\Temp\packageCertificate.pfx"/>
     42             <Parameter name="PowerShellModulePath" value="c:\dev\winget-cli\src\x64\Debug\PowerShell\Microsoft.WinGet.Client.psd1" />
     43         </TestRunParameters>
     44     </RunSettings>
     45 
     46 The easiest way to generate AppInstallerTestMsixInstaller.msix is by running makeappx pack for c:\dev\winget-cli\src\AppInstallerTestMsixInstaller\bin\x64\Debug.
     47 
     48 #### Log Files
     49 After running the E2E Tests, the logs can be found in the following paths:
     50 
     51 - **%LOCALAPPDATA%\Packages\WinGetDevCLI_8wekyb3d8bbwe\LocalState\DiagOutputDir**
     52 - **%LOCALAPPDATA%\E2ETestLogs**
     53 - **%TEMP%\WinGet\defaultState**
     54 
     55 ## LocalhostWebServer
     56 The src\Tool\LocalhostWebServer project generates an executable that serves static test files from a given directory path through a HTTPS local loopback server in order to maintain a closed and controlled repository for resources used for testing purposes.
     57 
     58 ### Start localhost web server
     59 
     60 The localhost web server needs to be running for the duration of the tests. The easiest way to run it is to use src\Tool\LocalhostWebServer\Run-LocalhostWebServer.ps1 in a different PowerShell session.
     61 
     62 |Parameter | Type | Description |
     63 |--|--|--|
     64 | **BuildRoot** | Mandatory | The output path of the LocalhostWebServer project. Normally something like <winget repo root>\src\<arch>\<configuration>\LocalhostWebServer
     65 | **StaticFileRoot** | Mandatory | Path to serve static root directory. If the directory path does not exist, a new directory will be created for you. |
     66 | **CertPath** | Mandatory | Path to HTTPS Developer Certificate. A self signed developer certificate will need to be created in order to  verify localhost https. |
     67 | **CertPassword** | Mandatory | HTTPS Developer Certificate Password |
     68 | **Port** | Optional | Port number [Default Port Number: 5001] |
     69 | **OutCertFile** | Optional | The exported certificate used |
     70 | **LocalSourceJson** | Optional | The local source definition. If set generates the source. |
     71 | **ForcedExperimentalFeatures** | Optional | Experimental features that should be forcibly enabled always. |
     72 
     73 ### How to create and trust an ASP.NET Core HTTPS Development Certificate
     74 Windows Package Manager Client (WinGet.exe) requires new sources added to the WinGet repositories be securely accessed through HTTPS. Therefore, in order to verify the LocalhostWebServer, you will need to create a self-signed development certificate to verify the localhost address. 
     75 
     76 - Open command prompt in administrator mode
     77 - Run **dotnet dev-certs https --trust** in the command line
     78 - Open up **certmgr** (search Manage User Certificates in Windows search bar) 
     79 - Locate the newly created localhost certificate in the Personal/Certificates folder with a friendly name of "ASP.NET Core HTTPS development certificate"
     80 - Right click on the certificate --> All Tasks --> Export..
     81 - Click Yes to export the private key
     82 - Export file using Personal Information Exchange (.pfx) file format
     83 - Create and confirm password using SHA256 encryption (any password will work, just make sure to remember it for later)
     84 - Save HTTPS development certificate and refer its certificate path and password when launching the Localhost Webserver
     85 
     86 ## WinGetSourceCreator
     87 The src\WinGetSourceCreator is a project that helps generate a new winget source for local development. It is consumed by IndexCreationTool, LocalhostWebServer and AppInstallerCLIE2ETests projects. It supports:
     88 - Prepare installers by signing them and placing then in the working directory and computing their hashes. For msix, signature hash is also supported.
     89 - Generate zip installers.
     90 - Generate the signed source.msix and index.db.
     91 
     92 LocalSource is the object that contains the definition of the source. A json serialized version of it is the input for IndexCreationTool and LocalhostWebServer.
     93 
     94 Example:
     95 ```
     96 {
     97   # If running E2E this is must be the StaticFileRoot used for the localhost web server
     98   "WorkingDirectory": "c:/dev/temp/TestLocalIndex",
     99 
    100   # The appx manifest to generate the source.msix file.
    101   "AppxManifest": "c:/dev/winget-cli/src/AppInstallerCLIE2ETests/TestData/Package/AppxManifest.xml",
    102 
    103   # A list of directories or files to copy. If a directory, it copies all the *.yaml files preserving subdirectories.
    104   "LocalManifests": [
    105     "c:/dev/winget-cli/src/x86/Release/AppInstallerCLIE2ETests/TestData/Manifests"
    106   ],
    107 
    108   # The signature to use.
    109   "Signature": {
    110     "CertFile": "cert.pfx",
    111     "Password": "1324",
    112 
    113     # If set it will modify the Package Identity Publisher in the AppxManifest.xml
    114     "Publisher": "CN:ThousandSunny"
    115   }
    116 
    117   # Installers that are already present in the machine, by default the installers will be signed using their Signature
    118   # property if set or the top level one.
    119   "LocalInstallers": [
    120     {
    121       "Type": "exe",
    122       "Input": "c:/dev/winget-cli/src/x64/Debug/AppInstallerTestExeInstaller\AppInstallerTestExeInstaller.exe",
    123 
    124       # Name of the installer to be copied and signed if needed.
    125       "Name": "AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe",
    126 
    127       # The token in the manifests for this installer. This will be replaces at copy manifests time.
    128       "HashToken": "<EXEHASH>"
    129 
    130       # Overrides top level one.
    131       "Signature": {
    132           "CertFile": "cert2.pfx",
    133           "Password": "2345",
    134       }
    135     },
    136     {
    137       "Type": "msi",
    138       "Input": "c:/dev/winget-cli/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestMsiInstaller.msi",
    139       "Name": "AppInstallerTestMsiInstaller/AppInstallerTestMsiInstaller.msi",
    140       "HashToken": "<MSIHASH>"
    141 
    142       # Don't sign this.
    143       "SkipSignature": true
    144     },
    145     {
    146       "Type": "msix",
    147       "Input": "D:/dev/temp/AppInstallerTestMsixInstaller.msix",
    148       "Name": "AppInstallerTestMsixInstaller/AppInstallerTestMsixInstaller.msix",
    149       "HashToken": "<MSIXHASH>",
    150 
    151       # Only supported by where type is msix. Package must be signed, either already signed or signed when copied.
    152       "SignatureToken": "<SIGNATUREHASH>",
    153     }
    154   ],
    155 
    156   # These are installers that are generated on the go. Currently only zip is supported.
    157   "DynamicInstallers": [
    158     {
    159       # Zip installers are never signed.
    160       "Type": "zip",
    161 
    162       # List of files to zip. Does not preserve subdirectories.
    163       "Input": [
    164         "D:/dev/temp/TestLocalIndex/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe",
    165         "D:/dev/temp/TestLocalIndex/AppInstallerTestMsiInstaller/AppInstallerTestMsiInstaller.msi",
    166         "D:/dev/temp/TestLocalIndex/AppInstallerTestMsixInstaller/AppInstallerTestMsixInstaller.msix"
    167       ],
    168 
    169       "Name": "AppInstallerTestZipInstaller/AppInstallerTestZipInstaller.zip",
    170 
    171       "HashToken": "<ZIPHASH>"
    172     }
    173   ],
    174 }
    175 ```