При написании инструмента для запуска тестов важно учитывать масштабируемость. Спросите себя: «Если бы мой инструмент запуска тестов должен был выполнить 200 тысяч тестовых случаев», сколько времени это заняло бы?»
Шардинг — одно из решений, доступных в Trade Federation. Он требует разбить все тесты, необходимые исполнителю, на несколько фрагментов, которые можно распараллелить.
На этой странице описывается, как сделать вашего бегуна шардируемым для Tradefed.
Интерфейс для реализации
Самый важный интерфейс, который необходимо реализовать, чтобы TF считался шардируемым, — это IShardableTest , который содержит два метода: split(int numShard)
и split()
.
Если шардинг будет зависеть от количества запрошенных шардов, следует реализовать split(int numShard)
. В противном случае реализуйте split()
.
При выполнении команды теста TF с параметрами шардинга --shard-count
и --shard-index
, TF перебирает все IRemoteTest
в поисках тех, которые реализуют IShardableTest
. Если они найдены, он вызывает split
для получения нового объекта IRemoteTest
для запуска подмножества тестовых случаев для конкретного шарда.
Что мне следует знать о реализации разделения?
- Ваш бегун может шардироваться только при определенных условиях; в этом случае возвращает
null
, если шард не был выполнен. - Постарайтесь разделить настолько, насколько это имеет смысл: разделите ваш исполнитель на отдельные единицы выполнения, которые подходят именно ему. Всё зависит от вашего исполнителя. Например: HostTest шардирован на уровне класса, каждый тестовый класс находится в отдельном шарде.
- Если это имеет смысл, добавьте несколько опций для управления шардингом. Например, у AndroidJUnitTest есть параметр
ajur-max-shard
который определяет максимальное количество шардов, на которые он может быть разделен, независимо от запрошенного количества.
Подробный пример реализации
Вот пример фрагмента кода, реализующего IShardableTest
, на который вы можете ссылаться. Полный код доступен по ссылке (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;
}
...
}
Этот пример просто создаёт новый экземпляр самого себя и задаёт ему параметры шарда. Однако логика разделения может существенно различаться от теста к тесту; и если она детерминирована и в совокупности даёт исчерпывающие подмножества, это допустимо.
Независимость
Шарды должны быть независимыми! Два шарда, созданные в результате реализации функции 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 не выполняет агрегацию результатов тестирования для сегментированных вызовов, вам необходимо убедиться, что ваша служба отчетности поддерживает эту функцию.