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 se o requisito da equipe de segurança foi atendido.

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

Primeiro, 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 . Nomeie o arquivo Website.Tests.ps1.

    Captura de tela do Visual Studio Code Explorer. A pasta deploy e o arquivo de teste são 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, você não precisa entender os detalhes do arquivo de teste e como ele funciona. Se estiver interessado, pode saber mais consultando o recurso listado no resumo do módulo.

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:

    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
    

    Seu processo de implantação ainda usa a mesma tarefa que usava anteriormente, mas as saídas das implantações agora 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:

      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. O valor é então publicado em uma variável de saída de estágio que tem o mesmo nome que a 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 :

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

    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 :

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

    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 seguinte código:

    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'
    

    Se o ficheiro não tiver o mesmo aspeto, atualize-o para corresponder a este exemplo e, em seguida, guarde-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. Em Azure DevOps, vá para o seu pipeline.

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

    Aguarde até que o pipeline conclua as fases 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 uma falha.

  5. Selecione a guia Testes .

    Captura de tela da interface do Azure DevOps que mostra a execução do pipeline. 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 por HTTP.

    Captura de tela da interface do Azure DevOps que mostra os resultados do teste de execução do pipeline. O teste reprovado é destacado.

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

Atualizar o arquivo Bicep

Agora que você sabe que sua definição de Bíceps 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 a aplicação do App Service do Azure e atualize-a para que inclua a propriedade httpsOnly na sua secção 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
            }
          ]
        }
      }
    }
    
  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 as fases 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/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.
    
  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. Repare que todo o pipeline termina com sucesso, incluindo o estágio de teste inicial SmokeTest. Este resultado 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