Sharded IRemoteTest Test Çalıştırıcısı Yazma

Bir test çalıştırıcısı yazarken ölçeklenebilirlik hakkında düşünmek önemlidir. Kendinize şunu sorun: "Test koşucum 200 bin test senaryosu çalıştırmak zorunda olsaydı" bu ne kadar sürerdi?

Sharding, Trade Federation'da bulunan cevaplardan biridir. Koşucunun ihtiyaç duyduğu tüm testleri paralelleştirilebilecek birkaç parçaya bölmeyi gerektirir.

Bu sayfa, koşucunuzu Tradefed için nasıl parçalanabilir hale getirebileceğinizi açıklar.

Uygulama arayüzü

TF tarafından parçalanabilir olarak kabul edilecek en önemli tek arabirim, iki yöntem içeren IShardableTest'tir : split(int numShard) ve split() .

Parçalamanız istenen parça sayısına bağlı olacaksa, split(int numShard) uygulamalısınız. Aksi takdirde, split() uygulayın.

--shard-count ve --shard-index sharding parametreleriyle bir TF test komutu yürütüldüğünde, TF IShardableTest uygulayanları aramak için tüm IRemoteTest IShardableTest . Bulunursa, belirli bir parça için test senaryolarının bir alt kümesini çalıştırmak üzere yeni bir IRemoteTest nesnesi almak için split çağırır.

Bölünmüş uygulama hakkında ne bilmeliyim?

  • Koşucunuz yalnızca bazı koşullara bağlı olarak parçalayabilir; bu durumda, parçalamadığınızda null değerini döndürün.
  • Mantıklı olduğu kadar bölmeye çalışın: Koşucunuzu onun için anlamlı olan yürütme birimine bölün. Bu gerçekten koşucunuza bağlı. Örneğin: HostTest , Sınıf düzeyinde parçalanır, her test sınıfı ayrı bir parçaya konur.
  • Mantıklıysa, parçalamayı biraz kontrol etmek için bazı seçenekler ekleyin. Örneğin: AndroidJUnitTest , istenen sayıdan bağımsız olarak bölünebileceği maksimum parça sayısını belirtmek için bir ajur-max-shard shard'a sahiptir.

Ayrıntılı örnek uygulama

Burada, IShardableTest uygulayan bir örnek kod parçacığı verilmiştir. Kodun tamamı (https://android.googlesource.com/platform/tools/tradefederation/+/refs/heads/master/test_framework/com/android/tradefed/testtype/InstalledInstrumentationsTest.java) adresinde mevcuttur.

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

Bu örnek basitçe kendisinin yeni bir örneğini oluşturur ve ona parça parametreleri ayarlar. Ancak, bölme mantığı testten teste tamamen farklı olabilir; ve deterministik olduğu ve toplu olarak ayrıntılı alt kümeler sağladığı sürece, sorun değil.

Bağımsızlık

Parçaların bağımsız olması gerekir! Runner'ınızda split uygulamanız tarafından oluşturulan iki parçanın birbirine bağımlı olması veya kaynakları paylaşmaması gerekir.

Parçaların bölünmesi deterministik olmalı! Bu aynı zamanda zorunludur, aynı koşullar göz önüne alındığında, split yönteminiz her zaman tam olarak aynı parça listesini aynı sırayla döndürmelidir.

NOT: Her parça farklı TF örneklerinde çalışabileceğinden, split mantığın birbirini dışlayan ve deterministik bir şekilde toplu olarak kapsamlı alt kümeler üretmesini sağlamak çok önemlidir.

Yerel olarak bir test nasıl parçalanır

Yerel bir TF'de bir testi parçalamak için komut satırına --shard-count seçeneğini eklemeniz yeterlidir.

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

Ardından TF, her parça için otomatik olarak komutlar oluşturacak ve bunları çalıştıracaktır.

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)

Test sonucu toplama

TF, parçalanmış çağrılar için herhangi bir test sonucu toplaması yapmadığından, raporlama hizmetinizin bunu desteklediğinden emin olmanız gerekir.