Je crée un service au-dessus de Google App Engine Datastore, qui est un magasin de données finalement cohérent. Pour mon application, c'est très bien.
Cependant, je développe des tests qui font des choses comme PUT object puis GET object et vérifiant les propriétés sur l'objet retourné. Malheureusement, parce que le magasin de données est finalement cohérent, ces tests simples ne sont pas reproductibles.
Comment testez-vous un service éventuellement cohérent?
google-app-engine
eventual-consistency
google-cloud-datastore
Doug Richardson
la source
la source
How can I reproducibly test an eventually consistent service?
- Tu ne peux pas. Vous devez supprimer le mot "reproductiblement" ou le mot "éventuellement"; vous ne pouvez pas avoir les deux.Réponses:
Tenez compte des exigences non fonctionnelles lors de la conception de vos tests fonctionnels - si votre service a une exigence non fonctionnelle de "Cohérente dans x (secondes / minutes / etc)", exécutez simplement les demandes PUT, attendez x, puis exécutez les demandes GET.
À ce stade, si les données ne sont pas encore «arrivées», vous pouvez considérer que la demande PUT n'est pas conforme à vos besoins.
la source
Vous voulez vraiment que vos tests soient rapides et cohérents. Si vous commencez à créer des tests qui peuvent parfois échouer en raison d'une cohérence éventuelle, vous ignorerez le test lorsqu'il échoue, et à quoi sert-il?
Créez un faux service qui gère les requêtes PUT et GET, mais a une opération supplémentaire pour le rendre cohérent. Votre test est alors:
Cela vous permet de tester le comportement de votre logiciel lorsque le GET récupère correctement l'objet PUT. Il vous permet également de tester le comportement de votre logiciel lorsque le GET ne trouve pas l'objet (ou l'objet correct) car le service n'est pas encore cohérent. Laissez simplement de côté l'appel
make_consistent()
.Il vaut toujours la peine d'avoir des tests qui interagissent avec le service réel, mais ils doivent s'exécuter en dehors de votre flux de travail de développement normal, car ils ne seront jamais fiables à 100% (par exemple, si le service est en panne). Ces tests doivent être utilisés pour:
la source
D'accord alors. "Que testez-vous" est la question clé.
Dans ce cas, vous devez vous moquer des services google et toujours renvoyer une réponse.
Dans ce cas, vous devez vous moquer des services google et toujours renvoyer l'erreur transitoire avant la réponse correcte
Vous devez injecter les vrais services google et exécuter le test. Mais! Le code que vous testez doit avoir la gestion des erreurs transitoires (réessayer) intégrée. Vous devriez donc obtenir une réponse cohérente. (sauf si google se comporte très mal)
la source
Utilisez l'une des options suivantes:
Malheureusement, vous devez choisir des valeurs magiques (N ou durée du sommeil) pour ces deux techniques.
la source
Si je comprends bien, la banque de données Google Cloud permet à la fois des requêtes fortement cohérentes et éventuellement cohérentes .
Le compromis est que les requêtes fortement cohérentes sont assez sévèrement limitées en taux (quelque chose avec lequel vous pouvez vivre pendant les tests).
Une possibilité peut être de placer vos requêtes dans la banque de données dans un wrapper qui peut permettre une forte cohérence à des fins de test.
Par exemple, vous pourriez avoir des méthodes appelées
start_debug_strong_consistency()
etend_debug_strong_consistency()
.La méthode de début créerait une clé qui peut être utilisée comme clé d'ancêtre pour toutes les requêtes suivantes, et la méthode de fin supprimerait la clé.
La seule modification des requêtes que vous testez serait d'appeler
setAncestor(your_debug_key)
si cette clé existe.la source
Une approche, intéressante en théorie mais pas toujours pratique, consiste à effectuer toutes les opérations d'écriture dans le système testé idempotentes . Cela signifie que, en supposant que votre code de test teste les choses dans un ordre séquentiel fixe, vous pouvez réessayer toutes les lectures et toutes les écritures individuellement jusqu'à ce que vous obteniez le résultat attendu, en recommençant jusqu'à ce que le délai que vous définissez dans le code de test soit dépassé. C'est-à-dire, faire la chose A1, réessayer si nécessaire jusqu'à ce que le résultat soit B1, puis faire la chose A2, réessayer si nécessaire jusqu'à ce que le résultat soit B2, et ainsi de suite.
Ensuite, vous n'avez pas besoin de vous soucier de vérifier les conditions préalables des opérations d'écriture, car les opérations d'écriture les vérifieront déjà pour vous, et vous devrez simplement les réessayer jusqu'à ce qu'elles réussissent!
Utilisez autant que possible les mêmes délais d'expiration "par défaut", qui peuvent être augmentés si l'ensemble du système devient plus lent, et remplacez les valeurs par défaut individuellement lors d'une nouvelle tentative d'opérations particulièrement lentes.
la source
Un service tel que Google App Engine Datastore est basé sur la réplication des données à travers plusieurs points de présence répartis mondialement (POP). Tout test d'intégration pour un service éventuellement cohérent est vraiment un test du taux de réplication de ce service sur son ensemble de POP. Le taux auquel le contenu est diffusé à chaque POP dans un service donné ne sera pas le même pour chaque POP au sein du service en fonction d'un certain nombre de facteurs, tels que la méthode de réplication et divers problèmes de transport Internet - ce sont deux exemples qui représentent la majorité des rapports dans tout service de magasin de données finalement cohérent (du moins, c'était mon expérience alors que je travaillais pour un CDN majeur).
Afin de tester efficacement la réplication d'un objet sur une plate-forme donnée, vous devez définir le test pour demander le même objet récemment placé à partir de chacun des POP du service. Je suggère de tester la liste des POP une à cinq fois ou jusqu'à ce que tous les POP de votre liste de POP signalent avoir l'objet. Voici un ensemble d'intervalles pour effectuer le test que vous êtes libre de régler: 1, 5, 60 minutes, 12 heures, 25 heures après l'avoir placé sur le magasin de données. La clé consiste à consigner les résultats à chaque intervalle pour un examen et une analyse ultérieurs afin d'avoir une idée de la capacité d'un service donné à répliquer des objets à l'échelle mondiale. Souvent, les services de banque de données ne tirent une copie locale vers un POP qu'une fois qu'elle a été demandée localement [le routage est effectué via le protocole BGP, c'est pourquoi votre test doit demander l'objet à chaque POP spécifique pour qu'il soit globalement valide pour une plate-forme donnée] . Dans le cas du magasin de données de Google, vous envisagez de configurer votre test pour interroger un objet donné à partir de "plus de 70 points de présence dans 33 pays"; vous devrez probablement obtenir la liste des adresses URL spécifiques à POP auprès de l'assistance Google [réf:https://cloud.google.com/about/locations/ ] ou si Google utilise Fastly pour la réplication, Fastly Support [ https://www.fastly.com/resources ].
Quelques avantages de cette méthode: 1) Vous aurez une idée de la plate-forme de réplication d'un service donné, connaître ses points forts et points faibles dans son ensemble à l'échelle mondiale [comme lors du test d'intégration]. 2) Quel que soit l'objet que vous testez, vous disposez d'un outil pour réchauffer le contenu [faites cette première demande qui crée la copie à un POP local donné] - vous offrant ainsi un moyen de vous assurer que le contenu est diffusé dans le monde entier avant que vos clients ne le demandent à n'importe où sur terre.
la source
J'ai de l'expérience avec Google App Engine Datastore. Fonctionnant localement, de manière surprenante, il est souvent plus "finalement" que "cohérent". L'exemple le plus simple: créez une nouvelle entité, puis récupérez-la. Souvent, au cours des 5 dernières années, j'ai vu le SDK exécuté localement ne pas trouver la nouvelle entité immédiatement, mais la trouver après environ une demi-seconde.
Cependant, contre les vrais serveurs Google, je n'ai pas vu ce comportement. Ils essaient de faire en sorte que votre client Datastore s'exécute toujours sur le même serveur de leur côté, donc généralement toutes les modifications sont immédiatement reflétées dans les requêtes.
Mon conseil pour les tests d'intégration est de les exécuter sur les vrais serveurs, et vous n'aurez probablement pas besoin de faire de faux sondages ou de retards pour obtenir vos résultats.
la source