Написать разделенный инструмент запуска тестов IRemoteTest

При написании средства запуска тестов важно думать о масштабируемости. Спросите себя: «Если бы моему исполнителю тестов пришлось запустить 200 000 тестовых примеров», сколько времени это заняло бы?

Шардинг - это один из ответов, доступных в Торговой федерации. Это требует разделения всех тестов, необходимых бегуну, на несколько частей, которые можно распараллелить.

На этой странице описывается, как сделать вашего раннера доступным для Tradefed.

Интерфейс для реализации

Самый важный интерфейс для реализации следует рассматривать shardable с TF является IShardableTest , который содержит два метода: split(int numShard) и split() .

Если ваш Sharding будет зависеть от количества осколков запрошенного, вы должны осуществить split(int numShard) . В противном случае, осуществить split() .

Когда команда теста TF выполняются с шардингом Parameters --shard-count и --shard-index , перебирает TF через все IRemoteTest искать те исполнитель IShardableTest . Если найдено, он будет вызывать split , чтобы получить новый IRemoteTest объект запустить подмножество тестов для конкретного осколка.

Что мне нужно знать о раздельной реализации?

  • Ваш бегун может осколить только при некоторых условиях; в этом случае возврата null , когда вы не шард.
  • Постарайтесь разделить столько, сколько это имеет смысл: разделите вашего бегуна на единицы выполнения, которые имеют для него смысл. Это действительно зависит от вашего бегуна. Например: HostTest является sharded на уровне класса, каждый класс испытаний помещают в отдельный осколка.
  • Если это имеет смысл, добавьте несколько параметров, чтобы немного контролировать сегментирование. Например: AndroidJUnitTest имеет ajur-max-shard , чтобы указать максимальное количество осколков он может разделить на, независимо от запрошенного числа.

Подробный пример реализации

Ниже приведен пример фрагмента кода реализации IShardableTest вы можете ссылаться. Полный код доступен по адресу (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;
    }
    ...
}

В этом примере просто создается новый экземпляр самого себя и задаются ему параметры шарда. Однако логика разделения может полностью отличаться от теста к тесту; и пока он детерминирован и дает в совокупности исчерпывающие подмножества, это нормально.

Независимость

Шарды должны быть независимыми! Два черепки , созданные вашей реализация split в вашем бегуне не должны иметь зависимости друг от друга или совместно использовать ресурсы.

Разделение осколков должно быть детерминированным! Это также является обязательным, поскольку один и тем же условием, ваш split метод всегда должен возвращать точно такой же список осколков в том же порядке.

Примечание: Поскольку каждый осколок может работать на разных экземплярах TF, важно обеспечить split логики Урожайность подмножества , которые являются взаимоисключающими и коллективно исчерпывающими детерминированным образом.

Как сегментировать тест локально

Чтобы шард тест на местном TF, вы можете просто добавить --shard-count опции в командной строке.

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

Затем TF автоматически создаст команды для каждого шарда и запустит их.

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)

Агрегация результатов теста

Поскольку TF не выполняет агрегирование результатов тестирования для сегментированных вызовов, вам необходимо убедиться, что ваша служба отчетов поддерживает его.