练习 - 向管道添加测试阶段
你的玩具公司的安全团队要求你验证是否只能通过 HTTPS 访问你的网站。 在本练习中,你将配置管道以运行冒烟测试,以检查是否满足安全团队的要求。
在此过程中,你将:
- 将测试脚本添加到存储库。
- 更新管道定义以添加测试阶段。
- 运行管道并观察到测试失败。
- 修复 Bicep 文件并观察到管道运行成功。
添加测试脚本
首先,添加一个测试脚本,以验证使用 HTTPS 时网站是否可访问,在使用不安全的 HTTP 协议时不可访问。
在 Visual Studio Code 中,在 部署 文件夹中创建新文件。 将文件 命名为Website.Tests.ps1。
将以下测试代码粘贴到文件中:
param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $HostName ) Describe 'Toy Website' { It 'Serves pages over HTTPS' { $request = [System.Net.WebRequest]::Create("https://$HostName/") $request.AllowAutoRedirect = $false $request.GetResponse().StatusCode | Should -Be 200 -Because "the website requires HTTPS" } It 'Does not serves pages over HTTP' { $request = [System.Net.WebRequest]::Create("http://$HostName/") $request.AllowAutoRedirect = $false $request.GetResponse().StatusCode | Should -BeGreaterOrEqual 300 -Because "HTTP is not secure" } }
此代码是一个 Pester 测试文件。 它需要一个名为
$HostName
的参数。 它针对主机名运行两个测试:- 尝试通过 HTTPS 连接到网站。 如果服务器使用 200 到 299 之间的 HTTP 响应状态代码进行响应,则测试会通过测试,这表示连接成功。
- 尝试通过 HTTP 连接到网站。 如果服务器以 300 或更高的 HTTP 响应状态代码进行响应,则测试通过。
在本练习中,无需了解测试文件的详细信息及其工作原理。 如果有兴趣,可以通过查看模块摘要中列出的资源来了解详细信息。
将 Bicep 文件的输出发布为阶段输出变量
前面步骤中创建的测试脚本需要一个主机名来进行测试。 Bicep 文件已包含一个输出,但需要将其发布为阶段输出变量,才能在冒烟测试中使用它。
在 Visual Studio Code 中,打开 deploy 文件夹中的 azure-pipelines.yml 文件。
在“部署”阶段,更新部署步骤,将输出发布到变量:
name: DeployBicepFile displayName: Deploy Bicep file inputs: connectedServiceName: $(ServiceConnectionName) deploymentName: $(Build.BuildNumber) ___location: $(deploymentDefaultLocation) resourceGroupName: $(ResourceGroupName) csmFile: deploy/main.bicep overrideParameters: > -environmentType $(EnvironmentType) deploymentOutputs: deploymentOutputs
部署过程仍使用与之前相同的任务,但部署的输出现在存储在名为“
deploymentOutputs
管道”的管道变量中。 输出变量的格式为 JSON。若要将 JSON 格式的输出转换为管道变量,请在部署步骤下方添加以下脚本步骤:
echo "##vso[task.setvariable variable=appServiceAppHostName;isOutput=true]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppHostName.value')" name: SaveDeploymentOutputs displayName: Save deployment outputs into variables env: DEPLOYMENT_OUTPUTS: $(deploymentOutputs)
如果部署成功完成,则该脚本将访问来自 Bicep 部署的每个输出值。 该脚本使用
jq
工具访问 JSON 输出的相关部分。 然后,该值将发布到与 Bicep 部署输出具有相同名称的阶段输出变量。注意
Pester 和 jq 都预安装在 Azure Pipelines 的 Microsoft 托管代理上。 无需执行任何特殊操作,即可在脚本步骤中使用它们。
保存文件。
向管道添加冒烟测试阶段
现在,可以添加运行测试的冒烟测试阶段。
在文件底部,为“SmokeTest”阶段添加以下定义:
jobs: - job: SmokeTest displayName: Smoke test variables: appServiceAppHostName: $[ stageDependencies.Deploy.DeployWebsite.outputs['DeployWebsite.SaveDeploymentOutputs.appServiceAppHostName'] ] steps:
此代码定义阶段和作业。 它还会在作业中创建一个名为
appServiceAppHostName
的变量。 此变量从你在上一部分中创建的输出变量中获取其值。在文件底部,向“SmokeTest”阶段添加以下步骤定义:
- task: PowerShell@2 name: RunSmokeTests displayName: Run smoke tests inputs: targetType: inline script: | $container = New-PesterContainer ` -Path 'deploy/Website.Tests.ps1' ` -Data @{ HostName = '$(appServiceAppHostName)' } Invoke-Pester ` -Container $container ` -CI
此步骤会运行一个 PowerShell 脚本,来运行之前使用 Pester 测试工具编写的测试脚本。
在文件底部,向“SmokeTest”阶段添加以下步骤定义:
name: PublishTestResults displayName: Publish test results condition: always() inputs: testResultsFormat: NUnit testResultsFiles: 'testResults.xml'
此步骤使用 Pester 创建的测试结果文件,并将其发布为管道测试结果。 你很快就会看到结果的展示方式。
请注意,步骤定义包括
condition: always()
。 该状况指示 Azure Pipelines 应始终发布测试结果,即使前面的步骤失败也是如此。 此条件很重要,因为任何失败的测试都会导致测试步骤失败,并且管道通常在失败的步骤后停止运行。保存文件。
验证并提交管道定义
验证 azure-pipelines.yml 文件是否如下代码所示:
trigger: batch: true branches: include: - main pool: Dafault variables: - name: deploymentDefaultLocation value: westus3 stages: - stage: Lint jobs: - job: LintCode displayName: Lint code steps: - script: | az bicep build --file deploy/main.bicep name: LintBicepCode displayName: Run Bicep linter - stage: Validate jobs: - job: ValidateBicepCode displayName: Validate Bicep code steps: - task: AzureResourceManagerTemplateDeployment@3 name: RunPreflightValidation displayName: Run preflight validation inputs: connectedServiceName: $(ServiceConnectionName) ___location: $(deploymentDefaultLocation) deploymentMode: Validation resourceGroupName: $(ResourceGroupName) csmFile: deploy/main.bicep overrideParameters: > -environmentType $(EnvironmentType) - stage: Preview jobs: - job: PreviewAzureChanges displayName: Preview Azure changes steps: - task: AzureCLI@2 name: RunWhatIf displayName: Run what-if inputs: azureSubscription: $(ServiceConnectionName) scriptType: 'bash' scriptLocation: 'inlineScript' inlineScript: | az deployment group what-if \ --resource-group $(ResourceGroupName) \ --template-file deploy/main.bicep \ --parameters environmentType=$(EnvironmentType) - stage: Deploy jobs: - deployment: DeployWebsite displayName: Deploy website environment: Website strategy: runOnce: deploy: steps: - checkout: self - task: AzureResourceManagerTemplateDeployment@3 name: DeployBicepFile displayName: Deploy Bicep file inputs: connectedServiceName: $(ServiceConnectionName) deploymentName: $(Build.BuildNumber) ___location: $(deploymentDefaultLocation) resourceGroupName: $(ResourceGroupName) csmFile: deploy/main.bicep overrideParameters: > -environmentType $(EnvironmentType) deploymentOutputs: deploymentOutputs - bash: | echo "##vso[task.setvariable variable=appServiceAppHostName;isOutput=true]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppHostName.value')" name: SaveDeploymentOutputs displayName: Save deployment outputs into variables env: DEPLOYMENT_OUTPUTS: $(deploymentOutputs) - stage: SmokeTest jobs: - job: SmokeTest displayName: Smoke test variables: appServiceAppHostName: $[ stageDependencies.Deploy.DeployWebsite.outputs['DeployWebsite.SaveDeploymentOutputs.appServiceAppHostName'] ] steps: - task: PowerShell@2 name: RunSmokeTests displayName: Run smoke tests inputs: targetType: inline script: | $container = New-PesterContainer ` -Path 'deploy/Website.Tests.ps1' ` -Data @{ HostName = '$(appServiceAppHostName)' } Invoke-Pester ` -Container $container ` -CI - task: PublishTestResults@2 name: PublishTestResults displayName: Publish test results condition: always() inputs: testResultsFormat: NUnit testResultsFiles: 'testResults.xml'
如果文件看起来不一样,请更新该文件以匹配此示例,然后保存它。
通过在 Visual Studio Code 终端中运行以下命令来提交更改并将其推送到 Git 存储库:
git add . git commit -m "Add test stage" git push
运行管道并审阅测试结果
在 Azure DevOps 中,转到你的管道。
选择管道的最新运行。
等待管道完成“Lint 分析”、“验证”和“预览”阶段。 尽管 Azure Pipelines 会自动更新具有最新状态的页面,但最好偶尔刷新页面。
选择“审阅”按钮,然后选择“批准”。
等待管道运行完成。
请注意,“部署”阶段成功完成。 “SmokeTest”阶段已完成,但出现错误。
选择“测试”选项卡。
请注意,测试摘要显示运行了两个测试。 一个通过,一个失败了。 失败的测试被列为“玩具网站。不通过 HTTP 提供页面”。
此文本指示网站未正确配置为满足安全团队的要求。
更新 Bicep 文件
现在,你知道你的 Bicep 定义不符合安全团队的要求,接下来,需要对其进行修复。
在 Visual Studio Code 中,打开 deploy 文件夹中的 main.bicep 文件。
查找 Azure 应用服务应用程序的定义,并将其更新,以便在其
httpsOnly
部分中包含properties
属性:resource appServiceApp 'Microsoft.Web/sites@2022-03-01' = { name: appServiceAppName ___location: ___location properties: { serverFarmId: appServicePlan.id httpsOnly: true siteConfig: { appSettings: [ { name: 'APPINSIGHTS_INSTRUMENTATIONKEY' value: applicationInsights.properties.InstrumentationKey } { name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' value: applicationInsights.properties.ConnectionString } ] } } }
保存文件。
通过在 Visual Studio Code 终端中运行以下命令来提交更改并将其推送到 Git 存储库:
git add . git commit -m "Configure HTTPS on website" git push
再次运行管道
在浏览器中,转到你的管道。
选择最近的运行。
等待管道完成“Lint 分析”、“验证”和“预览”阶段。 尽管 Azure Pipelines 会自动更新具有最新状态的页面,但最好偶尔刷新页面。
选择“预览”阶段,然后再次查看 What-if 结果。
请注意,What-if 命令已检测到
httpsOnly
属性值发生了更改:Resource and property changes are indicated with these symbols: + Create ~ Modify = Nochange The deployment will update the following scope: Scope: /subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/ToyWebsiteTest ~ Microsoft.Web/sites/toy-website-nbfnedv766snk [2021-01-15] + properties.siteConfig.localMySqlEnabled: false + properties.siteConfig.netFrameworkVersion: "v4.6" ~ properties.httpsOnly: false => true = Microsoft.Insights/components/toywebsite [2020-02-02] = Microsoft.Storage/storageAccounts/mystoragenbfnedv766snk [2021-04-01] = Microsoft.Web/serverfarms/toy-website [2021-01-15] Resource changes: 1 to modify, 3 no change.
返回到管道运行。
选择“ 审阅 ”按钮,然后选择“ 批准”。
等待管道运行完成。
请注意,整个管道成功完成,包括“SmokeTest”阶段。 此结果指示两个测试都已通过。
清理资源
完成练习后,可以删除资源,以便不再为这些资源付费。
在 Visual Studio Code 终端中,运行以下命令:
az group delete --resource-group ToyWebsiteTest --yes --no-wait
资源组将在后台删除。
Remove-AzResourceGroup -Name ToyWebsiteTest -Force