Test af infrastruktur som kode med Pulumi. Del 2

Hej alle sammen. I dag deler vi den afsluttende del af artiklen «Test af infrastruktur som kode med Pulumi», hvis oversættelse er forberedt specielt til studerende på kurset „DevOps praksis og værktøjer“.

Test af infrastruktur som kode med Pulumi. Del 2

Test af implementering

Den betragtede testmetode er en kraftfuld tilgang, der gør det muligt for os at udføre hvidkasse-test for at kontrollere detaljerne i vores infrastrukturkode. Dog begrænser det lidt, hvad vi kan teste. Testene udføres baseret på en in-memory implementeringsplan, der er oprettet af Pulumi før den faktiske implementering, og derfor kan selve implementeringen ikke testes. Til sådanne tilfælde har Pulumi et integrations-test-framework. Og disse to tilgange fungerer fremragende sammen!

Pulumi's integrations-test-framework er skrevet i Go, og det er ved hjælp af det, at vi tester størstedelen af vores interne kode. Hvis den tidligere betragtede modulære testmetode mindede mere om hvidkasse-test, så er integrationstest en sort boks. (Der er også muligheder for grundige interne tester.) Dette framework blev designet til at tage et komplet Pulumi-program og udføre forskellige livscyklusoperationer på det, såsom implementering af en ny stack fra bunden, opdatering med variationer og fjernelse, muligvis flere gange. Vi kører dem regelmæssigt (f.eks. om natten) og som stresstest.

(Vi arbejder på, at, så tilsvarende integrations-testfunktioner er tilgængelige i det native SDK for sprog. Du kan bruge integrations-testframeworket Go uafhængigt af det sprog, din Pulumi-program er skrevet i).

Når du kører programmet med dette framework, kan du kontrollere følgende:

  • Koden i dit projekt er syntaktisk korrekt og fungerer uden fejl.
  • Indstillingerne for stack-konfiguration og hemmeligheder fungerer og tolkes korrekt.
  • Dit projekt kan implementeres korrekt i den valgte cloud-udbyder.
  • Dit projekt kan opdateres korrekt fra sin oprindelige tilstand til N andre tilstande.
  • Dit projekt kan ødelægges og fjernes succesfuldt fra din cloud-udbyder.

Som vi snart vil se, kan dette framework også bruges til at udføre runtime-validering.

Simple integrations test

To see this in action, we will look at the repository pulumi/examples, as our team and the Pulumi community use it for testing their own pull requests, commits, and nightly builds.

Below is a simplified test of our example that provisions an S3 bucket and some other objects:

example_test.go:

package test
 
import (
    "os"
    "path"
    "testing"
 
    "github.com/pulumi/pulumi/pkg/testing/integration"
)
 
func TestExamples(t *testing.T) {
    awsRegion := os.Getenv("AWS_REGION")
    if awsRegion == "" {
        awsRegion = "us-west-1"
    }
    cwd, _ := os.Getwd()
    integration.ProgramTest(t, &integration.ProgramTestOptions{
        Quick:       true,
        SkipRefresh: true,
        Dir:         path.Join(cwd, "..", "..", "aws-js-s3-folder"),
        Config: map[string]string{
            "aws:region": awsRegion,
        },
    })
}

This test goes through the basic lifecycle of creating, updating, and destroying a stack for the folder aws-js-s3-folder. It will take about a minute to report the passed test:

$ go test .
PASS
ok      ... 43.993s

There are many parameters to configure the behavior of these tests. A complete list of options can be found in the structure ProgramTestOptions. For example, you can configure the Jaeger endpoint for tracing (Tracing), specify that you expect test failure during negative testing (ExpectFailure), apply a series of 'patches' to the program for state transitions (EditDirs) and more. Let's look at how to use them to validate application deployment.

Validating resource properties

The integration mentioned above ensures that our program 'works' — it does not crash. But what if we want to check the properties of the resulting stack? For example, that certain kinds of resources were (or were not) provisioned and that they have specific attributes.

Parameter ExtraRuntimeValidation for ProgramTestOptions allows us to look at the state captured by Pulumi after deployment (post-deployment state), so we can perform additional checks. This includes a complete snapshot of the resulting stack state, including configuration, exported output values, all resources and their property values, and all dependencies between resources.

To see a basic example of this, let's check that our program creates one S3 Bucket:

  integration.ProgramTest(t, &integration.ProgramTestOptions{
        // som tidligere...
        ExtraRuntimeValidation: func(t *testing.T, stack integration.RuntimeValidationStackInfo) {
            var foundBuckets int
            for _, res := range stack.Deployment.Resources {
                if res.Type == "aws:s3/bucket:Bucket" {
                    foundBuckets++
                }
            }
            assert.Equal(t, 1, foundBuckets, "Forventede at finde en enkelt AWS S3 Bucket")
        },
    })

Nu, når vi kører go test, vil det ikke kun gennemføre en række livscyklus test, men også, efter en vellykket udrulning af stakken, udføre en ekstra kontrol af den resulterende tilstand.

Runtime-tests

Indtil nu har alle testene været udelukkende om adfærden ved udrulning og Pulumi's ressource model. Hvad gør man, hvis man vil sikre, at den forberedte infrastruktur faktisk fungerer? For eksempel, om den virtuelle maskine kører, S3-bucket indeholder det, vi forventer, og så videre.

Du har måske allerede gættet, hvordan man gør det: option ExtraRuntimeValidation for ProgramTestOptions — er en fremragende mulighed for dette. På dette tidspunkt kører du en vilkårlig Go-test med adgang til den fulde tilstand af din programs ressourcer. Denne tilstand indeholder oplysninger såsom IP-adresser for de virtuelle maskiner, URL'er og alt hvad der er nødvendigt for at interagere med de opnåede cloud-applikationer og infrastruktur.

For eksempel eksporterer vores testprogram en egenskab webEndpoint på bucketen ved navn websiteUrl, som repræsenterer den fulde URL, hvor vi kan tilgå den konfigurerede index document. Selvom vi kunne dykke ned i tilstandsfilen for at finde bucket og læse denne egenskab direkte, eksporterer mange af vores stakke nyttige egenskaber som denne, som vi nemt kan bruge til verifikation:

integration.ProgramTest(t, &integration.ProgramTestOptions{
            // som før ...
        ExtraRuntimeValidation: func(t *testing.T, stack integration.RuntimeValidationStackInfo) {
            url := "http://" + stack.Outputs["websiteUrl"].(string)
            resp, err := http.Get(url)
            if !assert.NoError(t, err) {
                return
            }
            if !assert.Equal(t, 200, resp.StatusCode) {
                return
            }
            defer resp.Body.Close()
            body, err := ioutil.ReadAll(resp.Body)
            if !assert.NoError(t, err) {
                return
            }
            assert.Contains(t, string(body), "Hello, Pulumi!")
        },
    })

Ligesom vores tidligere runtime-kontroller vil denne kontrol blive udført straks efter stakken er oprettet, og alt dette som svar på et simpelt kald go test. Og det er kun toppen af isbjerget — alle testmulighederne i Go er tilgængelige, som du kan skrive i koden.

Kontinuerlig integration af infrastruktur

Det er godt at kunne køre tests på en bærbar computer, når der laves mange ændringer i infrastrukturen, for at teste dem inden de sendes til kodegennemgang. Men både vi og mange af vores kunder tester infrastrukturen på forskellige stadier af udviklingslivscyklussen:

  • I hver åben pull-anmodning for test før fusion.
  • I respons på hver commit for at dobbelttjekke, at fusioneringen blev udført korrekt.
  • Periodevis, for eksempel om natten eller ugentligt for yderligere test.
  • Som en del af ydeevne- eller stresstest, der normalt udføres over en længere periode og kører tests parallelt og/eller implementerer det samme program flere gange.

For hver af dem understøtter Pulumi integration med dit foretrukne kontinuerlige integrationssystem. Ved kontinuerlig integration giver det dig den samme testdækning for din infrastruktur, som du har for din applikationssoftware.

Pulumi har support for populære CI-systemer. Her er nogle af dem:

For mere information, se dokumentationen om Continuous Delivery.

Ephemeral miljøer

En meget kraftfuld mulighed, der åbner sig, er muligheden for at implementere ephemeral miljøer udelukkende til accepttest. Konceptet projekter og stacks Pulumi er designet til nemt at implementere og nedlægge fuldstændigt isolerede og uafhængige miljøer, alt med et par enkle CLI-kommandoer eller ved hjælp af et integrations-testframework.

Hvis du bruger GitHub, tilbyder Pulumi GitHub App, som hjælper dig med at forbinde accepttest til pull-anmodninger inden for din CI-pipeline. Installer bare appen i dit GitHub-repository, og Pulumi i dit CI, så vil der blive tilføjet oplysninger om forhandsvisning af infrastrukturen, opdateringer og testresultater til dine pull-anmodninger:

Test af infrastruktur som kode med Pulumi. Del 2

Når du bruger Pulumi til dine grundlæggende accepttest, får du nye automatiseringsmuligheder, der forbedrer teamets ydeevne og giver sikkerhed for kvaliteten af ændringerne.

Resultat

I denne artikel så vi, at når vi bruger generelle programmeringssprog, bliver mange metoder til softwareudvikling tilgængelige, som har været nyttige i udviklingen af vores applikationer. Disse inkluderer modulært test, integrationstest, samt deres interaktion for at gennemføre omfattende runtime-test. Tests er let at køre efter behov eller i dit CI-system.

Pulumi — er software med åben kildekode, det er gratis at bruge og fungerer med dine foretrukne programmeringssprog og skyverden — prøv det i dag!

→ Første del

Kilde: habr.com

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster