Quando scrivi un test runner, è importante pensare alla scalabilità. Chiedi a te stesso: "Se il mio test runner dovesse eseguire 200.000 casi di test", quanto tempo ci vorrebbe?
La suddivisione in parti è una delle risposte disponibili in Trade Federation. Richiede di suddividere tutti i test di cui ha bisogno il programma di esecuzione in più parti che possono essere parallelizzate.
Questa pagina descrive come rendere il tuo runner suddividibile in parti per Tradefed.
Interfaccia da implementare
L'interfaccia più importante da implementare per essere considerata shardabile da TF è IShardableTest, che contiene due metodi: split(int numShard)
e split()
.
Se la suddivisione dipenderà dal numero di shard richiesti, dovresti implementare split(int numShard)
. In caso contrario, implementa split()
.
Quando un comando di test TF viene eseguito con i parametri di suddivisione --shard-count
e
--shard-index
, TF esegue l'iterazione di tutti i IRemoteTest
per cercare quelli
che implementano IShardableTest
. Se viene trovato, chiamerà split
per recuperare un nuovo oggetto IRemoteTest
per eseguire un sottoinsieme di casi di test per uno specifico shard.
Cosa devo sapere sull'implementazione dell'organizzazione in più parti?
- Il tuo runner può eseguire lo sharding solo in base ad alcune condizioni. In questo caso, restituisci
null
quando non hai eseguito lo sharding. - Prova a suddividere il più possibile: suddividi il tuo runner in unità di esecuzione che abbiano senso. Dipende molto dal tuo runner. Ad esempio, HostTest è suddiviso a livello di classe, ogni classe di test viene inserita in uno shard separato.
- Se opportuno, aggiungi alcune opzioni per controllare un po' l'organizzazione in parti.
Ad esempio,
AndroidJUnitTest
ha un
ajur-max-shard
per specificare il numero massimo di shard in cui potrebbe essere suddiviso, indipendentemente dal numero richiesto.
Implementazione di un esempio dettagliato
Di seguito è riportato un esempio di snippet di codice che implementa IShardableTest
da utilizzare come riferimento. Il codice completo è disponibile all'indirizzo
(https://android.googlesource.com/platform/tools/tradefederation/+/refs/heads/android16-release/test_framework/com/android/tradefed/testtype/InstalledInstrumentationsTest.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;
}
...
}
Questo esempio crea semplicemente una nuova istanza di se stesso e imposta i parametri del frammento. Tuttavia, la logica di suddivisione può essere totalmente diversa da un test all'altro e, purché sia deterministica e generi sottoinsiemi collettivamente esaustivi, non ci sono problemi.
Indipendenza
Gli shard devono essere indipendenti. Due shard creati dall'implementazione di split
nel tuo runner non devono avere dipendenze tra loro o condividere risorse.
La suddivisione in frammenti deve essere deterministica. Anche questo è obbligatorio. Date le stesse condizioni, il metodo split
deve sempre restituire lo stesso elenco di frammenti nello stesso ordine.
NOTA: poiché ogni shard può essere eseguito su istanze TF diverse, è fondamentale assicurarsi che la logica split
generi sottoinsiemi mutuamente esclusivi e collettivamente esaustivi in modo deterministico.
Suddividere un test localmente
Per eseguire lo sharding di un test su un TF locale, puoi semplicemente aggiungere l'opzione --shard-count
alla 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 l'aggregazione dei risultati dei test per le invocazioni suddivise in parti, devi assicurarti che il tuo servizio di generazione di report lo supporti.