Cucumber-js: Ajoutez un partitionnement de travail personnalisé pour l'exécution parallèle.

Créé le 2 mars 2018  ·  7Commentaires  ·  Source: cucumber/cucumber-js

J'ai examiné la fonctionnalité de test parallèle expérimental, et je pense qu'elle peut avoir besoin d'un mécanisme pour contrôler le fonctionnement des différents esclaves.

En regardant cucumber-js/src/runtime/parallel/master.js:110 , je peux voir que les esclaves reçoivent du travail à partir d'une file d'attente. Cela sonne bien dans le cas général, mais je ne pouvais pas l'utiliser tel quel. Si mon cas est similaire à d'autres, j'aimerais suggérer qu'il devrait être possible de changer la stratégie de répartition du travail.

J'exécute des tests e2e à l'aide de Selenium, et différents tests accèdent à plusieurs bases de données différentes. Mes caractéristiques ressemblent donc à ;

Scenario: I can log in to the db1 database
 When I log in to the "db1" database
 Then ...

Scenario: I can create a user in the db2 database
 When I log in to the "db2" database
 Then ...

Ces bases de données sont des ressources partagées et sont restaurées sur un serveur, utilisées et supprimées pendant les tests. Si deux esclaves essayaient d'accéder à la même base de données en même temps, ils échoueraient.

De mon côté, je peux partitionner les fichiers de fonctionnalités en esclaves de manière appropriée ;

| feature         | database | slave |
| test1.feature   | dbA      |     1 |
| test2.feature   | dbB      |     1 |
| test3.feature   | dbC      |     2 |
| test4.feature   | dbC      |     2 |
| test5.feature   | dbC      |     2 |

Mais je ne vois pas de mécanisme permettant au lanceur de test parallèle de me demander où j'aimerais exécuter le scénario.

Serait-il possible d'avoir un point d'extension, un « partitionneur de travail personnalisé », qui demanderait quelque chose comme ;

getSlaveAffinity(featureFilePath, numberOfSlaves);

qui renverrait l'esclave sur lequel mettre le fichier de fonctionnalités ?

enhancement

Commentaire le plus utile

Quel est l'état actuel de cette fonctionnalité ? Je suis heureux de consacrer du temps à la mise en œuvre d'un POC si vous pouvez m'orienter dans la bonne direction. J'aime l'idée d'utiliser des balises sur des scénarios pour définir les ressources sur lesquelles ils nécessitent un mutex pour s'exécuter.

Tous les 7 commentaires

Hmm, donc actuellement, il utilise une file d'attente de cornichons (un scénario ou un exemple d'un aperçu de scénario), pas des fonctionnalités. Et il semble que l'objectif principal soit que deux scénarios conflictuels ne se déroulent pas en même temps. L'esclave sur lequel ils courent ne devrait pas avoir d'importance.

Réflexions sur une API comme

const {setParallelCanAssignFn} = require('cucumber')

// testCase = {uri, pickle}
// runningTestCases = [{uri, pickle}, ... ]
setParallelCanAssignFn((newTestCase, runningTestCases) => {
  // return true if newTestCase can be alongside the currently running test cases, false otherwise
})

Ensuite, lorsqu'un esclave est libre, il parcourt la liste des cornichons et lui attribue le premier pour lequel cette fonction renvoie true. La fonction par défaut renvoie toujours true.

Je l'aime bien! J'ai plein de petites pensées...

Cela semble définitivement être une option plus puissante, oui. Cela a pour effet de bien équilibrer le travail entre les travailleurs de la piscine. Dans ma suggestion précédente, je devais estimer le temps nécessaire à l'exécution d'un test et j'essayais d'équilibrer les choses ; pas aussi efficace ou facile que d'affecter des travailleurs inactifs !

Je préfère également l'utilisation de cornichons - mon partitionneur a fonctionné en gobbant pour trouver des fichiers de fonctionnalités, en les chargeant via l'analyseur Gherkin et en examinant les AST pour les étapes pertinentes - donc presque tout mon code recrée certains des éléments internes du concombre. Puisque vous les avez sous la main et que vous pouvez les passer en paramètres, cela me simplifie grandement la vie ! :) Je remarque que cette API est proche mais pas la même que pour les formateurs ; dans un formateur je peux écrire

    options.eventBroadcaster.on('test-case-started', ({ sourceLocation }) => {
        const { gherkinDocument, pickle } = options.eventDataCollector.getTestCaseData(sourceLocation);

Le cas de test transmis à la fonction pourrait-il obtenir les mêmes paramètres ou la même structure de cas de test ( { gherkinDocument, pickle } ) que les événements du formateur ? Je pense à un cas simple où vous devez partitionner en fonction de balises (disons @uses(DB1) que je trouverais sur le gherkinDocument. De plus, une API similaire peut signifier moins de documentation et plus de réutilisation de code ?

Juste pour clarifier, le setParallelCanAssignFn serait conçu pour s'exécuter sur le maître (« qui devrait obtenir le travail ? »), plutôt que sur les esclaves (« puis-je accepter ce travail ? »). Un implémenteur n'aurait pas besoin de s'inquiéter du multi-threading, n'est-ce pas, car le maître aurait la responsabilité unique et unique de l'attribution du travail ?

Je devrais également mentionner la séquence d'exécution, je pense. Ce mécanisme permet de rejeter un test puis de l'accepter ultérieurement. Donc un fichier de fonctionnalités écrit

Feature: X
    Scenario: A
    Scenario: B

Pourrait en fait être exécuté dans l'ordre [B,A] . Cela risque de casser la suite de tests de quelqu'un quelque part dans le monde. Non pas que cela devrait être le cas - l'ordre d'exécution ne devrait pas avoir d'importance - mais cela semble être la première fois que le concombre permettrait à un scénario d'être exécuté hors de l'ordre des fichiers de fonctionnalités.

En tout cas merci d'y avoir pensé !

Quel est l'état actuel de cette fonctionnalité ? Je suis heureux de consacrer du temps à la mise en œuvre d'un POC si vous pouvez m'orienter dans la bonne direction. J'aime l'idée d'utiliser des balises sur des scénarios pour définir les ressources sur lesquelles ils nécessitent un mutex pour s'exécuter.

Bonjour,

Je suis dans la même situation de réinitialisation de la base de données que @stevecooperorg et j'aimerais également pouvoir effectuer des tests en parallèle avec des balises.

Au moins, je pourrais créer un groupe "sans base de données" et un groupe "utilisant la base de données".

Ouais! Je suis aussi très désireux de cette fonctionnalité. Je vais préparer un POC (à moins que quelque chose n'arrive). Ce sera ma première contribution publique. Voyons comment ça se passe. Je suppose que je vais d'abord parcourir rapidement les directives.

@eman2673 Juste pour vous faire savoir: j'ai résolu le problème parallèle en démarrant une instance par tag via la CLI de l'hôte (scaleway pour moi).

Absolument pas natif cucumber-js mais c'est très efficace et permet d'avoir un test complet à chaque fusion sur master.
Et avec cette méthode, je pourrais aussi faire une instance par fichier de test si je le souhaite.

@adrien-carre Merci pour l'avertissement. Je cherche un peu plus de contrôle. Je veux jeter tous les travailleurs sur tout et ils ne fonctionnent comme par magie que sur des cas de test qui n'entrent pas en conflit sur le plan des ressources. Je souhaite également pouvoir marquer des scénarios comme utilisant plusieurs ressources (généralement 1 ou 2 tables). Essayer de mettre en œuvre l'approche @charlierudolph mentionnée ci-dessus.

Cette page vous a été utile?
0 / 5 - 0 notes