Test de système Cloud Functions à l'aide de Cloud Build et de Terraform

Ce tutoriel explique comment automatiser les tests de bout en bout sur une application créée à l'aide de Cloud Functions. Cloud Build exécute le pipeline de test, tandis que HashiCorp Terraform configure et supprime les ressources Google Cloud nécessaires à l'exécution des tests. Un déclencheur Cloud Build lance le pipeline après chaque commit de code.

Lorsque vous concevez des applications et évaluez les choix d'architecture, la testabilité est un élément clé à prendre en compte. La création et l'exécution régulière d'un ensemble complet de tests (tels que les tests unitaires automatisés, les tests d'intégration et les tests du système de bout en bout) sont essentielles pour vérifier que votre application se comporte comme prévu. Pour en savoir plus sur la méthode à adopter pour chaque catégorie de tests et des scénarios Cloud Functions différents, consultez le guide Bonnes pratiques en matière de tests.

En général, la création et l'exécution de tests unitaires sont des opérations simples, car ces tests sont isolés et indépendants de l'environnement d'exécution. En revanche, les tests d'intégration et les tests système s'avèrent plus complexes, en particulier dans un environnement cloud. La nécessité de tester le système de bout en bout est surtout pertinente pour les applications qui utilisent des technologies sans serveur telles que Cloud Functions. Ces applications sont souvent déclenchées par des événements et faiblement couplées. Elles peuvent donc être déployées indépendamment. Des tests complets de bout en bout sont essentiels pour vérifier que les fonctions répondent correctement aux événements dans l'environnement d'exécution Google Cloud.

Architecture

Le schéma d'architecture suivant présente les composants que vous utilisez dans ce tutoriel.

Schéma d'architecture des projets de compilation et de test

L'architecture comprend les composants suivants :

  • Un projet build qui héberge et exécute le pipeline Cloud Build
  • Un projet test qui héberge des ressources Google Cloud pour l'exemple d'application testé
    • L'application décrite dans le tutoriel intitulé Surveiller les performances des applications Web sans serveur est utilisée comme exemple d'application.
    • Les ressources Google Cloud de l'exemple d'application sont créées et détruites pour chaque itération de compilation, exception faite de la base de données Firestore qui est créée une seule fois, puis réutilisée par toutes les compilations suivantes.

Objectifs

  • Créer un pipeline Cloud Build pour exécuter des tests unitaires et des tests de bout en bout sur un exemple d'application créé avec Cloud Functions
  • Utiliser Terraform à partir de la compilation pour configurer et détruire les ressources Google Cloud requises par l'application
  • Utiliser un projet de test Google Cloud dédié pour isoler l'environnement de test
  • Créer un dépôt Git dans Cloud Source Repositories et ajouter un déclencheur Cloud Build pour exécuter la compilation de bout en bout après un commit

Coûts

Ce tutoriel utilise les composants facturables suivants de Google Cloud :

Obtenez une estimation des coûts en fonction de votre utilisation prévue à l'aide du simulateur de coût. Les nouveaux utilisateurs de Google Cloud peuvent bénéficier d'un essai gratuit.

Une fois que vous avez terminé ce tutoriel, vous pouvez éviter de continuer à payer des frais en supprimant les ressources que vous avez créées. Consultez la page Effectuer un nettoyage pour en savoir plus.

Avant de commencer

  1. Sélectionnez ou créez un projet Cloud. Il s'agit du projet test qui héberge l'exemple d'application.

    Accéder à la page "Sélecteur de projet"

  2. Notez l'ID du projet Google Cloud pour le projet test. Vous en aurez besoin dans la section suivante pour configurer votre environnement.
  3. Activez les Cloud Build, Cloud Functions, et Cloud Source Repositories requises pour ce projet.

    Activer les API

  4. Dans Cloud Console, accédez à la page Firestore.
  5. Accéder à la page Firestore
  6. Créez une base de données Firestore.

    Découvrir comment créer une base de données Firestore

  7. Sélectionnez ou créez un autre projet Google Cloud. Il s'agit du projet build qui héberge le pipeline Cloud Build.
  8. Accéder à la page "Gérer les ressources"
  9. Assurez-vous d'avoir activé la facturation pour vos projets Google Cloud.

    Découvrir comment activer la facturation

Configurer votre environnement

Dans ce tutoriel, vous exécutez des commandes dans Cloud Shell. Cloud Shell est un environnement shell dans lequel le SDK Cloud est déjà installé (y compris l'outil de ligne de commande gcloud), et dans lequel des valeurs sont déjà définies pour votre projet actuel. L'initialisation de Cloud Shell peut prendre quelques minutes.

  1. Dans Cloud Console pour le projet build, ouvrez Cloud Shell.

    Ouvrir Cloud Shell

  2. Définissez une variable pour l'ID de projet Google Cloud test que vous avez copié précédemment :

    export TEST_PROJECT=your-test-project-id
    

    Remplacez l'élément suivant :

    • your-test-project-id : ID de votre projet Google Cloud test.
  3. Définissez l'ID et le numéro du projet Google Cloud build actuel en tant que variables :

    export BUILD_PROJECT=$(gcloud config get-value core/project)
    export BUILD_PROJECT_NUM=$(gcloud projects list) \
        --filter="$BUILD_PROJECT" --format="value(PROJECT_NUMBER)"
    
  4. Définissez une variable pour la région de déploiement :

    export REGION=us-central1
    

    Bien que ce tutoriel utilise la région us-central1, vous pouvez la remplacer par n'importe quelle région où Cloud Functions est disponible.

  5. Clonez le dépôt contenant le code de l'exemple d'application utilisé dans ce tutoriel :

    git clone \
        https://github.com/GoogleCloudPlatform/solutions-serverless-web-monitoring.git
    
  6. Accédez au répertoire du projet :

    cd solutions-serverless-web-monitoring
    

Créer une infrastructure de test à l'aide de Terraform

Ce tutoriel permet de créer et détruire automatiquement des ressources Google Cloud dans le projet de test à l'aide de Terraform. La création de ressources indépendantes pour chaque compilation permet d'isoler les tests les uns des autres. Lorsque vous isolez des tests, des compilations peuvent avoir lieu simultanément et vous pouvez effectuer des assertions de test sur des ressources spécifiques. La destruction des ressources à la fin de chaque compilation vous permet de réduire les coûts.

Ce tutoriel déploie l'application décrite dans le tutoriel intitulé Surveiller les performances des applications Web sans serveur. Cette application se compose d'un ensemble de fonctions Cloud, de buckets Cloud Storage, de ressources Pub/Sub et d'une base de données Firestore. La configuration Terraform définit les étapes requises pour créer ces ressources. La base de données Firestore n'est pas déployée par Terraform, elle est créée une seule fois, puis réutilisée par tous les tests.

L'exemple de code suivant, issu du fichier de configuration Terraform main.tf, présente les étapes requises pour déployer la fonction Cloud trace. Pour connaître la configuration complète, consultez l'intégralité du fichier.

data "archive_file" "local_tracer_source" {
  type        = "zip"
  source_dir  = "./functions/tracer"
  output_path = "${var.local_output_path}/tracer.zip"
}

resource "google_storage_bucket_object" "gcs_tracer_source" {
  name   = "tracer.zip"
  bucket = "${google_storage_bucket.bucket_source_archives.name}"
  source = "${data.archive_file.local_tracer_source.output_path}"
}

resource "google_cloudfunctions_function" "function_tracer" {
  name = "tracer-${var.suffix}"
  project = "${var.project_id}"
  region = "${var.region}"
  available_memory_mb = "1024"
  entry_point = "trace"
  runtime = "nodejs8"
  trigger_http = "true"
  source_archive_bucket = "${google_storage_bucket.bucket_source_archives.name}"
  source_archive_object = "${google_storage_bucket_object.gcs_tracer_source.name}"
  environment_variables = {
    BUCKET_METRICS = "${google_storage_bucket.bucket_metrics.name}"
    ALLOWED_HOSTS = "${var.allowed_hosts}"
  }
}

// prevent unauthenticated invocations
resource "google_cloudfunctions_function_iam_binding" "tracer_disallow_unauthenticated" {
  project = "${var.project_id}"
  region = "${var.region}"
  cloud_function = "${google_cloudfunctions_function.function_tracer.name}"
  role = "roles/cloudfunctions.invoker"
  members = [
  ]
  depends_on = [
    google_cloudfunctions_function.function_tracer
  ]
}

Au cours de cette étape, vous allez exécuter la configuration Terraform pour déployer les ressources de test. Lors d'une prochaine étape, les ressources seront automatiquement déployées par Cloud Build.

  1. Dans Cloud Shell, initialisez Terraform :

    docker run -v $(pwd):/app -w /app hashicorp/terraform:0.12.0 init
    

    Vous devez utiliser l'image Docker Terraform publique. Docker est déjà installé dans Cloud Shell. Le répertoire de travail actuel est installé en tant que volume afin que le conteneur Docker puisse lire le fichier de configuration Terraform.

  2. Créez les ressources à l'aide de la commande apply Terraform :

    docker run -v $(pwd):/app -w /app hashicorp/terraform:0.12.0 apply \
        --auto-approve \
        -var "project_id=$TEST_PROJECT" \
        -var "region=$REGION" \
        -var "suffix=$TEST_PROJECT"
    

    Cette commande inclut des variables qui spécifient le projet Google Cloud et la région dans lesquels vous souhaitez créer les ressources de test. Elle inclut également un suffixe qui sert à créer des ressources nommées pour cette étape. Lors d'une prochaine étape, le suffixe approprié sera automatiquement fourni par Cloud Build.

    L'exécution de cette opération prend quelques minutes.

  3. Vérifiez que les ressources ont bien été créées dans le projet test :

    gcloud functions list --project $TEST_PROJECT
    

    Le résultat affiche trois fonctions Cloud dont le nom se termine par le suffixe fourni précédemment.

Exécuter des tests de bout en bout

Dans cette section, vous allez exécuter des tests de bout en bout sur l'infrastructure de test que vous avez déployée dans la section précédente.

Comme le montre l'extrait de code suivant, ces tests permettent de valider les scénarios de réussite et d'échec. Le pipeline de test peut se résumer comme suit :

  • Tout d'abord, le test appelle la fonction trace. Cet appel déclenche un flux d'événements via l'application, qui déclenche l'appel d'autres fonctions.
  • Ensuite, le test vérifie le comportement de chaque fonction et vérifie également que les objets sont écrits dans Cloud Storage, que les résultats sont conservés dans Firestore et que les alertes Pub/Sub sont générées en cas d'échec.
def test_e2e_pass():
  run_pipeline('http://www.example.com/', True)

def test_e2e_fail():
  run_pipeline('https://cloud.google.com/docs/tutorials', False)

def run_pipeline(url, should_pass):
  """Triggers the web analysis pipeline and verifies outputs of each stage.

  Args:
    url (str): The page to analyze.
    should_pass (bool): Whether the page should load within the threshold time.
  """
  trace_response = call_tracer(url)
  filename = assert_tracer_response(trace_response)
  assert_gcs_objects(filename)
  assert_firestore_doc(filename, should_pass)
  assert_pubsub_message(should_pass)

  # clean up
  delete_gcs_objects(filename)
  delete_firestore_doc(filename)

Pour exécuter les tests de bout en bout, procédez comme suit :

  1. Dans Cloud Shell, créez un environnement virtualenv. L'utilitaire virtualenv est déjà installé dans Cloud Shell.

    virtualenv venv
    
  2. Activez l'environnement virtualenv :

    source venv/bin/activate
    
  3. Installez les bibliothèques Python requises :

    pip install -r requirements.txt
    
  4. Exécutez les tests de bout en bout :

    python -m pytest e2e/ --tfstate terraform.tfstate
    

    Vous devez transmettre le fichier d'état Terraform contenant les détails des ressources de test créées à la section précédente.

    Les tests peuvent prendre quelques minutes. Un message indiquant la réussite de deux tests s'affiche. Vous pouvez ignorer tous les avertissements.

  5. Supprimez les ressources de test en exécutant la commande destroy Terraform :

    docker run -v $(pwd):/app -w /app hashicorp/terraform:0.12.0 destroy \
        --auto-approve \
        -var "project_id=$TEST_PROJECT" \
        -var "region=$REGION" \
        -var "suffix=$TEST_PROJECT"
    
  6. Vérifiez que les ressources sont détruites :

    gcloud functions list --project $TEST_PROJECT
    

    Il ne doit plus exister de fonctions Cloud dont le nom se termine par le suffixe fourni précédemment.

Envoyer le pipeline Cloud Build

Dans cette section, vous allez automatiser le pipeline de test à l'aide de Cloud Build.

Définir les autorisations Cloud Build

Vous devez exécuter Cloud Build à l'aide d'un compte de service Cloud Build. Les tests système exécutés par la compilation créent des fonctions Cloud, des buckets Cloud Storage, des ressources Pub/Sub et des documents Firestore avec lesquels ils interagissent. Pour cela, Cloud Build a besoin des éléments suivants :

Dans cette procédure, vous ajoutez d'abord les rôles appropriés, puis le compte de service Cloud Build.

  1. Dans Cloud Shell, ajoutez les rôles Cloud IAM appropriés au compte de service Cloud Build par défaut :

    for role in cloudfunctions.developer pubsub.editor storage.admin datastore.user; do \
        gcloud projects add-iam-policy-binding $TEST_PROJECT \
        --member="serviceAccount:$BUILD_PROJECT_NUM@cloudbuild.gserviceaccount.com" \
        --role="roles/$role"; \
        done
    
  2. Ajoutez ensuite le compte de service Cloud Build en tant qu'utilisateur serviceAccountUser du compte de service App Engine dans le projet de test :

    gcloud iam service-accounts add-iam-policy-binding \
        $TEST_PROJECT@appspot.gserviceaccount.com \
        --member="serviceAccount:$BUILD_PROJECT_NUM@cloudbuild.gserviceaccount.com" \
        --role=roles/iam.serviceAccountUser \
        --project $TEST_PROJECT
    

Envoyer une compilation manuelle

La compilation effectue quatre tâches logiques :

  • L'exécution des tests unitaires
  • Le déploiement de l'exemple d'application
  • L'exécution des tests de bout en bout
  • La destruction de l'exemple d'application

Vérifiez l'extrait de code suivant dans le fichier cloudbuild.yaml. Cet extrait présente les différentes étapes Cloud Build permettant de déployer l'exemple d'application à l'aide de Terraform et d'exécuter les tests de bout en bout.

# setup Terraform using public terraform Docker image
- id: terraform-init
  name: hashicorp/terraform:0.12.0
  args: ['init']

# deploy the required GCP resources
- id: terraform-apply
  name: hashicorp/terraform:0.12.0
  args: ['apply', '-auto-approve']
  env:
    - 'TF_VAR_project_id=$_TEST_PROJECT_ID'
    - 'TF_VAR_region=$_REGION'
    - 'TF_VAR_suffix=$BUILD_ID'

# run end-to-end tests to verify live interactions
- id: end-to-end-tests
  name: 'python:3.7-slim'
  entrypoint: /bin/sh
  args:
    - -c
    - 'pip install -r requirements.txt && python -m pytest e2e --tfstate terraform.tfstate'

Pour envoyer une compilation manuelle à Cloud Build et exécuter des tests de bout en bout, procédez comme suit :

  • Dans Cloud Shell, saisissez la commande suivante :

    gcloud builds submit --config cloudbuild.yaml \
        --substitutions=_REGION=$REGION,_TEST_PROJECT_ID=$TEST_PROJECT
    

    L'exécution de la compilation prend plusieurs minutes. Le processus de compilation se déroule selon les étapes ci-dessous :

    • Cloud Build effectue des substitutions pour fournir les variables qui spécifient le projet et la région Google Cloud des ressources de test que vous créez.

    • Cloud Build exécute ensuite la compilation dans le projet Google Cloud build. Les ressources de test sont créées dans le projet test distinct.

    Les journaux de compilation sont transmis à Cloud Shell pour vous permettre de suivre la progression de la compilation. Le flux de journalisation s'arrête une fois la compilation terminée. Les messages qui s'affichent indiquent que l'étape finale de compilation terraform-destroy a réussi et que la compilation est terminée.

Automatiser l'exécution des tests

L'un des principes clés de l'intégration continue (CI) consiste à exécuter régulièrement un ensemble complet de tests automatisés. En règle générale, le pipeline de test de compilation s'exécute pour chaque commit dans un dépôt de code partagé. Cette configuration permet de vérifier que chaque commit dans le dépôt partagé est testé et validé. Votre équipe est ainsi en mesure de détecter rapidement les problèmes.

Dans les sections suivantes, vous allez effectuer les actions ci-dessous :

  • Créer un dépôt Git dans Cloud Source Repositories
  • Ajouter un déclencheur Cloud Build permettant d'exécuter la compilation de bout en bout après chaque commit
  • Envoyer le code au dépôt pour déclencher la compilation

Créer un dépôt Cloud Source Repository et un déclencheur Cloud Build

  1. Dans Cloud Shell, créez un dépôt Cloud Source Repository :

    gcloud source repos create serverless-web-monitoring
    
  2. Dans Cloud Console, ouvrez la page Déclencheurs de Cloud Build.

    Accéder à la page "Déclencheurs"

  3. Cliquez sur Créer un déclencheur.

    La page Créer un déclencheur s'affiche.

  4. Indiquez les options suivantes :

    • Dans le champ Nom, saisissez end-to-end-tests.
    • Sous Événement, sélectionnez Déployer sur une branche.
    • Sous Source, sélectionnez le dépôt severless-web-monitoring et la branche ^master$.
    • Sous Configuration de compilation, sélectionnez Fichier de configuration Cloud Build.
    • Dans le champ Emplacement du fichier de configuration Cloud Build, saisissez cloudbuild.yaml.
    • Pour ajouter une substitution de variable qui spécifie la région Google Cloud dans laquelle les ressources de test seront créées, cliquez sur Ajouter une variable :

      • Variable : _REGION
      • Valeur : your-test-region

        Remplacez l'élément suivant :

        • your-test-region : valeur de la variable $REGION dans Cloud Shell.
    • Pour ajouter une autre substitution de variable qui spécifie l'ID du projet qui hébergera les ressources de test, cliquez sur Ajouter une variable :

      • Variable : _TEST_PROJECT_ID
      • Valeur : your-test-project

        Remplacez l'élément suivant :

        • your-test-project : valeur de la variable $TEST_PROJECT dans Cloud Shell.
  5. Cliquez sur Créer pour enregistrer le déclencheur de compilation.

Démarrer la compilation

  1. Dans Cloud Shell, ajoutez le dépôt en tant que nouveau dépôt distant dans votre configuration git :

    git remote add csr \
        https://source.developers.google.com/p/$BUILD_PROJECT/r/serverless-web-monitoring
    
  2. Pour déclencher la compilation, transférez le code vers le dépôt :

    git push csr master
    
  3. Répertoriez les compilations les plus récentes :

    gcloud builds list --limit 3
    

    Le résultat affiche une compilation à l'état WORKING, indiquant que la compilation s'est déclenchée comme prévu.

  4. Copiez l'ID de la compilation WORKING pour l'étape suivante.

  5. Diffusez les journaux de compilation dans Cloud Console :

    gcloud builds log --stream build-id
    

    Remplacez l'élément suivant :

    • build-id : ID de la compilation WORKING que vous avez copié à l'étape précédente.

    Le flux de journalisation s'arrête une fois la compilation terminée. Les messages qui s'affichent indiquent que l'étape finale de compilation terraform-destroy a réussi et que la compilation est terminée.

Nettoyer

Pour éviter que les ressources utilisées dans ce tutoriel soient facturées sur votre compte Google Cloud Platform, procédez comme suit :

Supprimer le projet

  1. Dans Cloud Console, accédez à la page Gérer les ressources.

    Accéder à la page Gérer les ressources

  2. Dans la liste des projets, sélectionnez le projet que vous souhaitez supprimer, puis cliquez sur Supprimer.
  3. Dans la boîte de dialogue, saisissez l'ID du projet, puis cliquez sur Arrêter pour supprimer le projet.

Étapes suivantes