Exercício - Adicione um estágio de teste ao seu pipeline

Concluído

A equipa de segurança da sua empresa de brinquedos pediu-lhe para verificar se o seu website está acessível apenas através de HTTPS. Neste exercício, você configurará seu pipeline para executar um teste de fumaça que verifica os requisitos da equipe de segurança.

Durante o processo, você:

  • Adicione um script de teste ao repositório.
  • Atualize sua definição de pipeline para adicionar um estágio de teste.
  • Execute o pipeline e observe a falha do teste.
  • Corrija o arquivo Bicep e observe o pipeline ser executado com êxito.

Adicionar um script de teste

Aqui, você adicionará um script de teste para verificar se o site está acessível quando HTTPS é usado e não acessível quando o protocolo HTTP não seguro é usado.

  1. No Visual Studio Code, crie um novo arquivo na pasta de implantação chamada Website.Tests.ps1.

    Captura de tela do Visual Studio Code Explorer, com a pasta deploy e o arquivo de teste mostrados.

  2. Cole o seguinte código de teste no arquivo:

    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"
        }
    
    }
    

    Este código é um arquivo de teste Pester. Requer um parâmetro chamado $HostName. Ele executa dois testes em relação ao nome do host:

    • Tente se conectar ao site por HTTPS. O teste passa se o servidor responder com um código de status de resposta HTTP entre 200 e 299, o que indica uma conexão bem-sucedida.
    • Tente se conectar ao site por HTTP. O teste passa se o servidor responder com um código de status de resposta HTTP de 300 ou superior.

    Para os fins deste exercício, não é importante que você entenda os detalhes do arquivo de teste e como ele funciona. Forneceremos links no resumo para que você possa saber mais se estiver interessado.

Publique a saída do arquivo Bicep como uma variável de saída de estágio

O script de teste que você criou nas etapas anteriores requer um nome de host para testar. Seu arquivo Bicep já inclui uma saída, mas antes que você possa usá-lo em seus testes de fumaça, você precisa publicá-lo como uma variável de saída de estágio.

  1. No Visual Studio Code, abra o arquivo azure-pipelines.yml na pasta deploy .

  2. No estágio Implantar, atualize a etapa de implantação para publicar as saídas em uma variável:

    - 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
    

    Agora, seu processo de implantação ainda usa a mesma tarefa que anteriormente, mas as saídas das implantações são armazenadas em uma variável de pipeline chamada deploymentOutputs. A variável de saída é formatada como JSON.

  3. Para converter as saídas formatadas em JSON em variáveis de pipeline, adicione a seguinte etapa de script abaixo da etapa de implantação:

    - 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)
    

    Se a implantação for concluída com êxito, o script acessará o valor de cada saída da implantação do Bicep. O script usa a jq ferramenta para acessar a parte relevante da saída JSON. Em seguida, o valor é publicado em uma variável de saída de estágio com o mesmo nome da saída de implantação do Bicep.

    Nota

    O Pester e o jq estão pré-instalados em agentes hospedados pela Microsoft para o Azure Pipelines. Você não precisa fazer nada de especial para usá-los em uma etapa de script.

  4. Guarde o ficheiro.

Adicione um estágio de teste de fumaça ao seu pipeline

Agora, você pode adicionar uma etapa de teste de fumaça que executa seus testes.

  1. Na parte inferior do arquivo, adicione a seguinte definição para o estágio SmokeTest :

    - stage: SmokeTest
      jobs:
      - job: SmokeTest
        displayName: Smoke test
        variables:
          appServiceAppHostName: $[ stageDependencies.Deploy.DeployWebsite.outputs['DeployWebsite.SaveDeploymentOutputs.appServiceAppHostName'] ]
    

    Este código define o estágio e um trabalho. Ele também cria uma variável no trabalho chamado appServiceAppHostName. Essa variável obtém seu valor da variável de saída que você criou na seção anterior.

  2. Na parte inferior do arquivo, adicione a seguinte definição de etapa ao estágio SmokeTest :

    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
    

    Esta etapa executa um script do PowerShell para executar o script de teste que você escreveu anteriormente usando a ferramenta de teste Pester.

  3. Na parte inferior do arquivo, adicione a seguinte definição de etapa ao estágio SmokeTest :

    - task: PublishTestResults@2
      name: PublishTestResults
      displayName: Publish test results
      condition: always()
      inputs:
        testResultsFormat: NUnit
        testResultsFiles: 'testResults.xml'
    

    Esta etapa usa o arquivo de resultados de teste que o Pester cria e o publica como resultados de teste de pipeline. Você verá como os resultados serão exibidos em breve.

    Observe que a definição de etapa inclui condition: always(). Essa condição indica ao Azure Pipelines que ele sempre deve publicar os resultados do teste, mesmo que a etapa anterior falhe. Essa condição é importante porque qualquer teste com falha fará com que a etapa de teste falhe e, normalmente, o pipeline para de ser executado após uma etapa com falha.

  4. Guarde o ficheiro.

Verificar e confirmar sua definição de pipeline

  1. Verifique se o arquivo azure-pipelines.yml se parece com o código a seguir:

    trigger:
      batch: true
      branches:
        include:
        - main
    
    pool:
      vmImage: ubuntu-latest
    
    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'
    

    Caso contrário, atualize-o para corresponder a este exemplo e salve-o.

  2. Confirme e envie suas alterações para o repositório Git executando os seguintes comandos no terminal do Visual Studio Code:

    git add .
    git commit -m "Add test stage"
    git push
    

Execute o pipeline e revise o resultado do teste

  1. No seu navegador, vá para o seu pipeline.

  2. Selecione a execução mais recente do seu pipeline.

    Aguarde até que o pipeline conclua os estágios Lint, Validate e Preview . Embora o Azure Pipelines atualize automaticamente a página com o status mais recente, é uma boa ideia atualizá-la ocasionalmente.

  3. Selecione o botão Rever e, em seguida, selecione Aprovar.

    Aguarde até que a execução do pipeline termine.

  4. Observe que o estágio Implantar é concluído com êxito. A etapa SmokeTest termina com um erro.

    Captura de tela da interface do Azure DevOps que mostra os estágios de execução do pipeline. A etapa SmokeTest relata falha.

  5. Selecione a guia Testes .

    Captura de tela da interface do Azure DevOps que mostra a execução do pipeline, com a guia Testes realçada.

  6. Observe que o resumo do teste mostra que dois testes foram executados. Um passou e outro falhou. O teste que falhou está listado como Toy Website.Não serve páginas sobre HTTP.

    Captura de tela da interface do Azure DevOps que mostra os resultados do teste de execução do pipeline, com o teste com falha realçado.

    Este texto indica que o site não foi configurado corretamente para atender aos requisitos da sua equipe de segurança.

Atualizar o arquivo Bicep

Agora que você identificou que sua definição de Bicep não atende aos requisitos da sua equipe de segurança, você a corrigirá.

  1. No Visual Studio Code, abra o arquivo main.bicep na pasta deploy .

  2. Encontre a definição para o aplicativo do Serviço de Aplicativo do Azure e atualize-a para incluir a httpsOnly propriedade em sua properties área:

    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
            }
          ]
        }
      }
    }
    
  3. Guarde o ficheiro.

  4. Confirme e envie suas alterações para o repositório Git executando os seguintes comandos no terminal do Visual Studio Code:

    git add .
    git commit -m "Configure HTTPS on website"
    git push
    

Execute o pipeline novamente

  1. No seu navegador, vá para o seu pipeline.

  2. Selecione a execução mais recente.

    Aguarde até que o pipeline conclua os estágios Lint, Validate e Preview . Embora o Azure Pipelines atualize automaticamente a página com o status mais recente, é uma boa ideia atualizá-la ocasionalmente.

  3. Selecione o estágio Visualizar e revise os resultados hipotéticos novamente.

    Observe que o comando what-if detetou a alteração no valor da httpsOnly propriedade:

    Resource and property changes are indicated with these symbols:
      + Create
      ~ Modify
      = Nochange
    
    The deployment will update the following scope:
    
    Scope: /subscriptions/f0750bbe-ea75-4ae5-b24d-a92ca601da2c/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.
    
  4. Volte para a execução do pipeline.

  5. Selecione o botão Rever e, em seguida, selecione Aprovar.

    Aguarde até que a execução do pipeline termine.

  6. Observe que todo o pipeline termina com sucesso, incluindo o estágio SmokeTest . Este sucesso indica que ambos os testes foram aprovados.

    Captura de tela da interface do Azure DevOps que mostra uma execução de pipeline bem-sucedida.

Limpar os recursos

Agora que concluiu o exercício, pode remover os recursos para não ser cobrado por eles.

No terminal de código do Visual Studio, execute o seguinte comando:

az group delete --resource-group ToyWebsiteTest --yes --no-wait

O grupo de recursos é excluído em segundo plano.

Remove-AzResourceGroup -Name ToyWebsiteTest -Force