Scrivi un runner del test IRemoteTest con sharding

Quando si scrive un test runner, è importante considerare la scalabilità. Domande "Se il mio corridore di test doveva eseguire 200.000 scenari di test" quanto tempo ci vuole?

Lo sharding è una delle risposte disponibili nella Trade Federation. Richiede suddividere tutti i test di cui il runner ha bisogno in diversi blocchi parallelizzato.

In questa pagina viene descritto come impostare il tuo runner con sharding per il Tradefed.

Interfaccia da implementare

L'unica interfaccia più importante da implementare per poter essere considerata soggetta a sharding TF è IShardableTest che include due metodi: split(int numShard) e split().

Se lo sharding dipende dal numero di shard richiesti, deve implementare split(int numShard). In caso contrario, implementa split().

Quando viene eseguito un comando di test TF con i parametri di partizionamento orizzontale --shard-count e --shard-index, TF esegue l'iterazione di tutti i IRemoteTest per cercarne uno che implementa IShardableTest. Se lo trovi, chiamerà split a ottieni un nuovo oggetto IRemoteTest per eseguire un sottoinsieme di scenari di test per uno specifico shard.

Che cosa devo sapere sull'implementazione frazionata?

  • Il runner può eseguire lo sharding solo in alcune condizioni; in questo caso restituisci null quando non hai eseguito lo sharding.
  • Cerca di dividere il più possibile: dividi il tuo runner in unità di più efficace. Dipende dal tuo runner. Per esempio: Test Host lo sharding è a livello di classe, ogni classe di test viene inserita in uno shard separato.
  • Se lo ritieni opportuno, aggiungi alcune opzioni per controllare un po' lo sharding. Ad esempio: AndroidJUnitTest ha un valore ajur-max-shard per specificare il numero massimo di shard che può indipendentemente dal numero richiesto.

Esempio di implementazione dettagliato

Ecco un esempio di snippet di codice che implementa IShardableTest che puoi riferimento. Il codice completo è disponibile all'indirizzo

/**
 * 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;
    }
    ...
}

Questo esempio crea semplicemente una nuova istanza di se stesso e imposta lo shard parametri. Tuttavia, la logica di suddivisione può essere completamente diversa eseguire un test; e purché sia deterministico e produca collettivamente esaustivi, non è un problema.

Indipendenza

Gli shard devono essere indipendenti. Due shard creati dall'implementazione split nel runner non deve avere dipendenze tra loro o condividere Google Cloud.

La suddivisione degli shard deve essere deterministica. Anche questo passaggio è obbligatorio, dato che stesse condizioni, il tuo metodo split dovrebbe sempre restituire esattamente lo stesso elenco di più piccoli nello stesso ordine.

NOTA: poiché ogni shard può essere eseguito su istanze TF diverse, è fondamentale assicurati che la logica split produca sottoinsiemi che si escludono a vicenda e esaustivi in modo deterministico.

Esegui lo sharding di un test in locale

Per eseguire lo sharding di un test su un TF locale, puoi semplicemente aggiungere l'opzione --shard-count a la riga di comando.

tf >run host --class com.android.tradefed.UnitTests --shard-count 3

TF genererà automaticamente i comandi per ogni shard e li eseguirà.

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)

Aggregazione dei risultati del test

Poiché TF non esegue alcuna aggregazione dei risultati di test per le chiamate con sharding, assicurati che il tuo servizio di reporting la supporti.