Exercício – Adicionar uma fase de teste ao pipeline

Concluído

A equipe de segurança da empresa de brinquedos pediu para você verificar se o site só é acessível via 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ê vai:

  • Adicionar um script de teste ao repositório.
  • Atualizar a definição de pipeline para adicionar uma fase de teste.
  • Executar o pipeline e observar a falha do teste.
  • Corrigir o arquivo Bicep e observar a execução de pipeline bem-sucedida.

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 de implantação 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 do Pester. Ele requer um parâmetro chamado $HostName. Ele executa dois testes em relação ao nome do host:

    • Tente se conectar ao site via HTTPS. O teste será aprovado 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 via HTTP. O teste é aprovado se o servidor responde com um código de status de resposta HTTP igual a 300 ou superior.

    Para fins deste exercício, você não precisa entender os detalhes do arquivo de teste e como ele funciona. Se estiver interessado, saiba mais verificando o recurso listado no resumo do módulo.

Publicar a saída do arquivo Bicep como uma variável de saída da fase

O script de teste criado nas etapas anteriores exige um nome de host para teste. O arquivo Bicep já inclui uma saída, mas, para usá-lo nos smoke tests, você precisa publicá-lo como uma variável de saída da fase.

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

  2. Na fase 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
    

    O processo de implantação ainda usa a mesma tarefa que antes, 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 como 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 ferramenta jq para acessar a parte relevante da saída JSON. Em seguida, o valor é 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.

    Observação

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

  4. Salve o arquivo.

Adicionar uma fase de smoke test ao pipeline

Agora você pode adicionar uma fase de smoke test que executa os seus testes.

  1. No final do arquivo, adicione a seguinte definição à fase SmokeTest:

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

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

  2. No final do arquivo, adicione a seguinte definição de etapa à fase 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
    

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

  3. No final do arquivo, adicione a seguinte definição de etapa à fase SmokeTest:

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

    Essa etapa usa o arquivo de resultados do teste que o Pester cria e publica como resultados do teste de pipeline. Você verá como os resultados sã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 de 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. Salve o arquivo.

Verificar a definição de pipeline e fazer commit dela

  1. Verifique se o arquivo azure-pipelines.yml é semelhante ao 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 arquivo não tiver a mesma aparência, atualize-o para corresponder a este exemplo e salve-o.

  2. Faça commit e efetue push das alterações no repositório Git executando os seguintes comandos no terminal do Visual Studio Code:

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

Executar o pipeline e examinar o resultado do teste

  1. No Azure DevOps, vá para o seu pipeline.

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

    Aguarde até que o pipeline conclua as fases Efetuar Lint, Validar e Visualizar. Embora o Azure Pipelines atualize automaticamente a página com o status mais recente, é uma boa ideia atualizar a página ocasionalmente.

  3. Escolha o botão Examinar e selecione Aprovar.

    Aguarde a conclusão da execução de pipeline.

  4. Observe que a fase Implantar foi concluída com êxito. A fase SmokeTest é concluída com um erro.

    Captura de tela da interface do Azure DevOps que mostra os estágios de execução do pipeline. O estágio 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 está realçada.

  6. Observe que o resumo do teste mostra que dois testes foram executados. Um passou e um falhou. O teste que falhou está listado como Toy Website não fornece páginas via HTTP.

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

    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 a sua definição do 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 do aplicativo do Serviço de Aplicativo do Azure e atualize-a para incluir a propriedade httpsOnly em sua seçã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. Salve o arquivo.

  4. Faça commit e efetue push das alterações no repositório Git executando os seguintes comandos no terminal do Visual Studio Code:

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

Executar o pipeline novamente

  1. No navegador, acesse seu pipeline.

  2. Selecione a execução mais recente.

    Aguarde até que o pipeline conclua as fases Efetuar Lint, Validar e Visualizar. Embora o Azure Pipelines atualize automaticamente a página com o status mais recente, é uma boa ideia atualizar a página ocasionalmente.

  3. Selecione a fase Visualizar e examine os resultados do teste de hipóteses novamente.

    Observe que o comando de teste de hipóteses detectou a alteração no valor da propriedade 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.
    
  4. Volte à execução de pipeline.

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

    Aguarde a conclusão da execução de pipeline.

  6. Observe que todo o pipeline é concluído com êxito, incluindo a fase SmokeTest. Esse 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 você concluiu o exercício, remova os recursos para não ser cobrado por eles.

No terminal do Visual Studio Code, execute o seguinte comando:

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

O grupo de recursos será excluído em segundo plano.

Remove-AzResourceGroup -Name ToyWebsiteTest -Force