Lorsque vous écrivez un outil d'exécution de tests, il est important de penser à l'évolutivité. Demander vous-même, « si mon lanceur de test a dû exécuter 200 000 scénarios de test » combien de temps cela prendrait-il ?
La segmentation est l'une des réponses disponibles au sein de la Fédération du commerce. Cela nécessite diviser tous les tests dont l'exécuteur a besoin en plusieurs fragments pouvant être en parallèle.
Cette page explique comment rendre votre exécuteur partitionnable pour Tradefed.
Interface à implémenter
La seule interface la plus importante à implémenter pour être considérée comme pouvant être segmentée par
TF signifie
IShardableTest
qui contient deux méthodes: split(int numShard)
et split()
.
Si votre partitionnement dépend du nombre de partitions demandées, vous devez implémenter split(int numShard)
. Sinon, implémentez split()
.
Lorsqu'une commande de test TF est exécutée avec les paramètres de fractionnement --shard-count
et --shard-index
, TF itère sur tous les IRemoteTest
pour rechercher ceux qui implémentent IShardableTest
. Si elle est trouvée, elle appelle split
pour obtenir un nouvel objet IRemoteTest
afin d'exécuter un sous-ensemble de cas de test pour un fragment spécifique.
Que dois-je savoir sur l'implémentation de la division ?
- Votre exécuteur peut partitionner sous certaines conditions uniquement : Dans ce cas, renvoyez
null
lorsque vous n'avez pas effectué la segmentation. - Essayez de diviser autant que possible : divisez votre exécuteur en unités d'exécution qui ont du sens. Cela dépend vraiment de votre exécuteur. Par exemple, HostTest est partitionné au niveau de la classe. Chaque classe de test est placée dans un segment distinct.
- Si c'est judicieux, ajoutez des options pour contrôler un peu la segmentation.
Par exemple:
AndroidJUnitTest
comporte un champ
ajur-max-shard
pour indiquer le nombre maximal de segments à répartir, quel que soit le nombre demandé.
Exemple d'implémentation détaillé
Voici un exemple d'extrait de code implémentant IShardableTest
que vous pouvez consulter. Le code complet est disponible à l’adresse
https://android.googlesource.com/platform/tools/tradefederation/+/refs/heads/main/test_framework/com/android/tradefed/testtype/InstallezInstrumentationsTest.java.
/**
* Runs all instrumentation found on current device.
*/
@OptionClass(alias = "installed-instrumentation")
public class InstalledInstrumentationsTest
implements IDeviceTest, IResumableTest, IShardableTest {
...
/** {@inheritDoc} */
@Override
public Collection<IRemoteTest> split(int shardCountHint) {
if (shardCountHint > 1) {
Collection<IRemoteTest> shards = new ArrayList<>(shardCountHint);
for (int index = 0; index < shardCountHint; index++) {
shards.add(getTestShard(shardCountHint, index));
}
return shards;
}
// Nothing to shard
return null;
}
private IRemoteTest getTestShard(int shardCount, int shardIndex) {
InstalledInstrumentationsTest shard = new InstalledInstrumentationsTest();
try {
OptionCopier.copyOptions(this, shard);
} catch (ConfigurationException e) {
CLog.e("failed to copy instrumentation options: %s", e.getMessage());
}
shard.mShardIndex = shardIndex;
shard.mTotalShards = shardCount;
return shard;
}
...
}
Cet exemple crée simplement une instance de lui-même et lui attribue des paramètres de fragment. Cependant, la logique de fractionnement peut être totalement différente tester pour tester ; tant qu'il est déterministe et génère collectivement des sous-ensembles exhaustifs, ce n'est pas grave.
L'indépendance
Les fragments doivent être indépendants. Les deux fragments créés par votre implémentation de split
dans votre exécuteur ne doivent pas dépendre les uns des autres ni partager de ressources.
Le fractionnement des fragments doit être déterministe. Cette étape est également obligatoire,
les mêmes conditions, votre méthode split
doit toujours renvoyer exactement la même liste de
segments dans le même ordre.
REMARQUE: Étant donné que chaque segment peut s'exécuter sur différentes instances TF, il est essentiel
vous assurer que la logique split
génère des sous-ensembles qui s'excluent mutuellement ;
collectivement exhaustives et de manière déterministe.
Diviser un test en local
Pour fractionner un test sur un TF local, vous pouvez simplement ajouter l'option --shard-count
à la ligne de commande.
tf >run host --class com.android.tradefed.UnitTests --shard-count 3
TF génère ensuite automatiquement des commandes pour chaque fragment et les exécute.
tf >l i
Command Id Exec Time Device State
3 0m:03 [null-device-2] running stub on build 0 (shard 1 of 3)
3 0m:03 [null-device-1] running stub on build 0 (shard 0 of 3)
3 0m:03 [null-device-3] running stub on build 0 (shard 2 of 3)
Agrégation des résultats de test
Étant donné que TF n'effectue aucune agrégation des résultats des tests pour les invocations fractionnées, vous devez vous assurer que votre service de création de rapports le prend en charge.