Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

Escriba un ejecutor de pruebas de IRemoteTest Sharded

Al escribir un corredor de pruebas, es importante pensar en la escalabilidad. Pregúntese, "si mi corredor de pruebas tuviera que ejecutar 200K casos de prueba", ¿cuánto tiempo tomaría?

Sharding es una de las respuestas disponibles en Trade Federation. Requiere dividir todas las pruebas que necesita el corredor en varios fragmentos que se pueden paralelizar.

Esta página describe cómo hacer que su corredor sea compartible para Tradefed.

Interfaz a implementar

La interfaz más importante para poner en práctica para ser considerado shardable por TF es IShardableTest , que contiene dos métodos: split(int numShard) y split() .

Si su sharding va a depender del número de fragmentos solicitado, se deben implementar split(int numShard) . De lo contrario, aplicar split() .

Cuando un comando de prueba TF se ejecuta con sharding parámetros --shard-count y --shard-index , itera a través de todos TF IRemoteTest a buscar unos aplicación IShardableTest . Si lo encuentra, se llamará split para obtener una nueva IRemoteTest objeto de ejecutar un subconjunto de casos de prueba para un fragmento específico.

¿Qué debo saber sobre la implementación dividida?

  • Tu corredor puede fragmentar solo en algunas condiciones; en ese caso el retorno null cuando no fragmento.
  • Intente dividir tanto como tenga sentido: divida su corredor en la unidad de ejecución que tenga sentido para él. Realmente depende de tu corredor. Por ejemplo: HostTest se fragmentados a nivel de clase, cada clase de prueba se pone en un fragmento separado.
  • Si tiene sentido, agregue algunas opciones para controlar un poco la fragmentación. Por ejemplo: AndroidJUnitTest tiene una ajur-max-shard para especificar el número máximo de fragmentos que podría dividir en, independientemente de la cantidad solicitada.

Implementación de ejemplo detallada

He aquí un fragmento de código de ejemplo, la aplicación de IShardableTest puede hacer referencia. El código completo está disponible en (https://android.googlesource.com/platform/tools/tradefederation/+/refs/heads/master/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;
    }
    ...
}

Este ejemplo simplemente crea una nueva instancia de sí mismo y le asigna parámetros de fragmentación. Sin embargo, la lógica de división puede ser totalmente diferente de una prueba a otra; y siempre que sea determinista y genere subconjuntos colectivamente exhaustivos, está bien.

Independencia

¡Los fragmentos deben ser independientes! Dos fragmentos creados por su implementación de split en su corredor no deben tener dependencias entre sí o compartir recursos.

¡La división de fragmentos debe ser determinista! Esto también es obligatoria, dadas las mismas condiciones, su split método debería devolver siempre exactamente la misma lista de fragmentos en el mismo orden.

NOTA: Puesto que cada fragmento se puede ejecutar en diferentes instancias TF, es crítico para asegurar que las split rendimientos de lógica de subconjuntos que son mutuamente excluyentes y colectivamente exhaustiva de una manera determinista.

Cómo fragmentar una prueba localmente

Para fragmentar una prueba en una TF local, puede simplemente añadir el --shard-count opción de la línea de comandos.

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

Entonces TF generará automáticamente comandos para cada fragmento y los ejecutará.

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)

Agregación de resultados de prueba

Dado que TF no realiza ninguna agregación de resultados de prueba para invocaciones fragmentadas, debe asegurarse de que su servicio de informes lo admita.