Tests automatisés de systèmes distribués

a marqué ce sujet comme résolu.

Bonjour tout le monde,

Pour mon plaisir personnel, je m’intéresse à l’algorithme de consensus Raft et j’ai commencé ma propre implémentation. Mon problème arrive au moment où je veux le tester.

Par exemple, une phase de l’algorithme est l’élection d’un leader. Les différents noeuds du système doivent communiquer entre eux et élire un leader. Pour chaque terme, un seul leader peut être élu. Actuellement, pour vérifier que mon implémentation fonctionne, je lance trois serveurs localement et je garde un oeil sur les logs pour vérifier que c’est bien le cas. Mais cette méthode n’est pas vraiment optimale et demande beaucoup de travail manuel. Il n’existe pas de "décision centrale" (une base de données ou quelque chose du genre) donc chaque noeud garde en mémoire qui est le leader pour le terme actuel.

Ce qui m’amène à ma question : existe-t-elle des bonnes pratiques pour tester ce genre de systèmes distribués ? Si ça peut aider dans vos réponses, j’utilise Java et Spring.

Salut.

Je me pose naïvement la question, mais plutôt que de faire un gros setup compliqué avec un vrai réseau, n’as-tu pas moyen d’instancier trois serveurs directement en mémoire en leur passant des fausses connections ?

Je pense par exemple à mon cas au boulot où les serveurs communiquent entre eux avec gRPC, l’implémentation Go de la lib gRPC permet de créer des "fausses" connexions en mémoire, qui reproduisent exactement l’interface et le comportement des vraies connexions tcp sous-jacentes, ce qui permet de tester un service en utilisant directement un vrai client, mais sans jamais s’embêter avec une connexion réseau et en ayant tout le loisir de manipuler le serveur directement (pour inspecter son état…) en plus de l’interroger, depuis le même code, à travers le client.

Rien que ce genre de truc devrait rendre tes tests d’intégration beaucoup plus simples, à mon avis, à savoir disposer directement de serveurs que tu peux manipuler et inspecter depuis le test.

+1 -0

Salut.

Je me pose naïvement la question, mais plutôt que de faire un gros setup compliqué avec un vrai réseau, n’as-tu pas moyen d’instancier trois serveurs directement en mémoire en leur passant des fausses connections ?

Oui, ça devrait être faisable. J’utilise un HttpClient pour faire mes appels, je devrais pouvoir remplacer ça par des simples appels "locaux" en cas de test (soit c’est supporté par HttpClient, soit je peux facilement coder ça). C’est une bonne idée.

Mais ce avec quoi j’ai encore du mal, c’est que par exemple, si j’ai 3 serveurs actifs et que le leader crashe, les deux serveurs restants doivent organiser une élection et un seul de ces serveurs doit devenir le nouveau leader. Mais ce qui me pose problème, c’est:

  • Comment simuler un crash ? Quand je teste manuellement, je kill mon serveur tomcat. Je pourrais faire en sorte que mon mock de HttpClient puisse rendre un certain serveur inaccessible mais ça me semble un peu bizarre. Ou en fait, je pourrais tuer mon instance en mémoire…
  • Ces tests sont plus ou moins aléatoires. Quand je teste manuellement, tout se passe bien dans 90% des cas et dans 10%, y a une race condition qui fait que plusieurs leaders sont élus. Comment faire ne sorte que mon test arrive à déceler ce genre de cas à tous les coups?

Intéressant comme problématique. Y a forcément quelque chose en Java pour mocker un HttpClient. Ça te permettrait d’avoir des tests reproductibles.

+0 -0

Quand c’est possible, le mieux est de faire en sorte que ta logique métier (ton algorithme) ne dépend pas directement de classes comme HttpClient mais d’une interface que tu définis (inversion de dépendances)

Cette interface sera implémentée par une classe qui, elle, utilisera potentiellement HttpClient.

L’intérêt est de faire en sorte que tu puisses utiliser un test double pour tes tests. Avec ce genre d’outils, ça devient facile de simuler les connexions réseau mais aussi les cas particuliers (comme un serveur qui ne répond plus)

Quand tu ne peux pas faire ça, tu peux mocker HttpClient avec une bibliothèque comme Mockito. Ca te permet de définir une réponse pour un appel spécifique à une méthode donnée. Tu peux donc faire en sorte qu’un serveur ne réponde plus.

Pour la gestion des cas aléatoires, ça peut devenir un peu plus compliqué mais l’objectif est de maîtriser l’aléatoire pour que ça ne soit plus un problème dans les tests (notamment en utilisant le même procédé d’inversion de dépendances et en respectant les principes de test F.I.R.S.T.).

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte