Base de données du tableau de bord VTS

Pour prendre en charge un tableau de bord d'intégration continue évolutif, performant et flexible, le backend du tableau de bord VTS doit être soigneusement conçu avec une solide compréhension des fonctionnalités de la base de données. Google Cloud Datastore est une base de données NoSQL qui offre des garanties transactionnelles ACID et une cohérence éventuelle ainsi qu'une forte cohérence au sein des groupes d'entités. Cependant, la structure est très différente de celle des bases de données SQL (et même de Cloud Bigtable) ; au lieu de tableaux, de lignes et de cellules, il existe des types, des entités et des propriétés.

Les sections suivantes décrivent la structure des données et les modèles d'interrogation permettant de créer un backend efficace pour le service Web du tableau de bord VTS.

Entités

Les entités suivantes stockent les résumés et les ressources des exécutions de tests VTS :

  • Entité de test . Stocke les métadonnées sur les exécutions d’un test particulier. Sa clé est le nom du test et ses propriétés incluent le nombre d'échecs, le nombre de réussites et la liste des échecs du scénario de test à partir du moment où les tâches d'alerte le mettent à jour.
  • Entité d'exécution de test . Contient les métadonnées des exécutions d’un test particulier. Il doit stocker les horodatages de début et de fin du test, l'ID de build de test, le nombre de cas de test réussis et échoués, le type d'exécution (par exemple pré-soumission, post-soumission ou locale), une liste de liens de journal, l'hôte le nom de la machine et le récapitulatif de la couverture.
  • Entité d’informations sur le périphérique . Contient des détails sur les appareils utilisés lors du test. Il comprend l'ID de build de l'appareil, le nom du produit, la cible de build, la branche et les informations ABI. Ceci est stocké séparément de l’entité d’exécution de test pour prendre en charge les exécutions de tests multi-appareils de manière un-à-plusieurs.
  • Profilage de l'entité d'exécution de point . Résume les données collectées pour un point de profilage particulier au cours d’une exécution de test. Il décrit les étiquettes des axes, le nom du point de profilage, les valeurs, le type et le mode de régression des données de profilage.
  • Entité de couverture . Décrit les données de couverture recueillies pour un fichier. Il contient les informations du projet Git, le chemin du fichier et la liste des décomptes de couverture par ligne dans le fichier source.
  • Entité d'exécution de scénario de test . Décrit le résultat d'un scénario de test particulier issu d'une exécution de test, y compris le nom du scénario de test et son résultat.
  • Entité Favoris de l'utilisateur . Chaque abonnement utilisateur peut être représenté dans une entité contenant une référence au test et l'ID utilisateur généré à partir du service utilisateur App Engine. Cela permet une interrogation bidirectionnelle efficace (c'est-à-dire pour tous les utilisateurs abonnés à un test et pour tous les tests favoris d'un utilisateur).

Regroupement d'entités

Chaque module de test représente la racine d'un groupe d'entités. Les entités d'exécution de test sont à la fois des enfants de ce groupe et des parents d'entités de périphérique, d'entités de point de profilage et d'entités de couverture pertinentes pour le test et l'ancêtre d'exécution de test respectifs.

Figure 1 . Ascendance de l’entité de test.

Point clé : lors de la conception de relations d'ascendance, vous devez équilibrer la nécessité de fournir des mécanismes d'interrogation efficaces et cohérents avec les limitations imposées par la base de données.

Avantages

L'exigence de cohérence garantit que les opérations futures ne verront pas les effets d'une transaction jusqu'à ce qu'elle soit validée, et que les transactions passées soient visibles pour les opérations actuelles. Dans Cloud Datastore, le regroupement d'entités crée des îlots de forte cohérence en lecture et en écriture au sein du groupe, qui, dans ce cas, regroupe l'ensemble des exécutions de tests et des données liées à un module de test. Cela offre les avantages suivants :

  • Les lectures et les mises à jour pour tester l'état du module par des tâches d'alerte peuvent être traitées comme atomiques
  • Vue cohérente garantie des résultats des scénarios de test dans les modules de test
  • Interrogation plus rapide dans les arbres d'ascendance

Limites

Il n'est pas conseillé d'écrire dans un groupe d'entités à une vitesse supérieure à une entité par seconde, car certaines écritures peuvent être rejetées. Tant que les tâches d'alerte et le téléchargement ne s'effectuent pas à un rythme supérieur à une écriture par seconde, la structure est solide et garantit une forte cohérence.

En fin de compte, le plafond d'une écriture par module de test et par seconde est raisonnable car les exécutions de tests prennent généralement au moins une minute, y compris la surcharge du framework VTS ; à moins qu'un test soit exécuté de manière cohérente et simultanée sur plus de 60 hôtes différents, il ne peut pas y avoir de goulot d'étranglement en écriture. Cela devient d'autant plus improbable que chaque module fait partie d'un plan de test qui prend souvent plus d'une heure. Les anomalies peuvent facilement être gérées si les hôtes exécutent les tests en même temps, provoquant de courtes rafales d'écritures sur les mêmes hôtes (par exemple en détectant les erreurs d'écriture et en réessayant).

Considérations de mise à l'échelle

Une exécution de test n'a pas nécessairement besoin d'avoir le test comme parent (par exemple, elle peut prendre une autre clé et avoir le nom du test, l'heure de début du test comme propriétés) ; cependant, cela échangera une forte cohérence contre une cohérence éventuelle. Par exemple, la tâche d'alerte peut ne pas voir un instantané mutuellement cohérent des exécutions de tests les plus récentes au sein d'un module de test, ce qui signifie que l'état global peut ne pas décrire une représentation entièrement précise de la séquence d'exécutions de tests. Cela peut également avoir un impact sur l'affichage des exécutions de tests au sein d'un seul module de test, qui ne constitue pas nécessairement un instantané cohérent de la séquence d'exécution. Finalement, l'instantané sera cohérent, mais rien ne garantit que les données les plus récentes le seront.

Cas de tests

Un autre goulot d'étranglement potentiel concerne les tests volumineux avec de nombreux cas de test. Les deux contraintes opérationnelles sont le débit d'écriture maximum au sein d'un groupe d'entités d'une par seconde, ainsi qu'une taille de transaction maximale de 500 entités.

Une approche consisterait à spécifier un scénario de test qui a une exécution de test comme ancêtre (de la même manière que les données de couverture, les données de profilage et les informations sur l'appareil sont stockées) :

Figure 2 . Les cas de test descendent des exécutions de tests (NON RECOMMANDÉ).

Bien que cette approche offre atomicité et cohérence, elle impose de fortes limites aux tests : si une transaction est limitée à 500 entités, alors un test ne peut pas contenir plus de 498 cas de test (en supposant qu'il n'y ait pas de couverture ou de données de profilage). Si un test devait dépasser ce chiffre, une seule transaction ne pourrait pas écrire tous les résultats du scénario de test en même temps, et la division des scénarios de test en transactions distinctes pourrait dépasser le débit d'écriture maximal du groupe d'entités d'une itération par seconde. Comme cette solution n’évoluera pas correctement sans sacrifier les performances, elle n’est pas recommandée.

Cependant, au lieu de stocker les résultats du scénario de test en tant qu'enfants de l'exécution de test, les scénarios de test peuvent être stockés indépendamment et leurs clés fournies à l'exécution de test (une exécution de test contient une liste d'identifiants de ses entités de cas de test) :

Figure 3 . Cas de test stockés indépendamment (RECOMMANDÉ).

À première vue, cela peut sembler rompre la solide garantie de cohérence. Cependant, si le client dispose d'une entité d'exécution de test et d'une liste d'identifiants de scénario de test, il n'a pas besoin de construire une requête ; il peut à la place obtenir directement les cas de test par leurs identifiants, ce qui est toujours garanti pour être cohérent. Cette approche allège considérablement la contrainte sur le nombre de cas de test qu'une exécution de test peut avoir tout en gagnant en cohérence sans menacer une écriture excessive au sein d'un groupe d'entités.

Modèles d'accès aux données

Le tableau de bord VTS utilise les modèles d'accès aux données suivants :

  • Favoris des utilisateurs . Peut être interrogé à l'aide d'un filtre d'égalité sur les entités favorites des utilisateurs ayant l'objet utilisateur App Engine particulier comme propriété.
  • Liste des tests . Requête simple des entités de test. Pour réduire la bande passante nécessaire au rendu de la page d'accueil, une projection peut être utilisée sur les décomptes de réussite et d'échec afin d'omettre la liste potentiellement longue des ID de scénario de test ayant échoué et d'autres métadonnées utilisées par les tâches d'alerte.
  • Tests . L'interrogation des entités d'exécution de test nécessite un tri sur la clé (horodatage) et un filtrage éventuel sur les propriétés d'exécution de test telles que l'ID de build, le nombre de réussites, etc. En effectuant une requête ancêtre avec une clé d'entité de test, la lecture est fortement cohérente. À ce stade, tous les résultats du scénario de test peuvent être récupérés à l'aide de la liste des ID stockés dans une propriété d'exécution de test ; cela garantit également un résultat fortement cohérent de par la nature des opérations d'obtention de la banque de données.
  • Données de profilage et de couverture . L'interrogation des données de profilage ou de couverture associées à un test peut être effectuée sans récupérer également d'autres données d'exécution de test (telles que d'autres données de profilage/couverture, des données de scénario de test, etc.). Une requête ancêtre utilisant les clés d'entité test test et test run récupérera tous les points de profilage enregistrés pendant l'exécution du test ; en filtrant également sur le nom du point de profilage ou le nom de fichier, une seule entité de profilage ou de couverture peut être récupérée. De par la nature des requêtes ancêtres, cette opération est fortement cohérente.

Pour plus de détails sur l'interface utilisateur et des captures d'écran de ces modèles de données en action, consultez l'interface utilisateur du tableau de bord VTS .