Parçalı bir IRemoteTest test çalıştırıcısı yazın

Bir test çalıştırıcısı yazarken ölçeklenebilirliği düşünmek önemlidir. Kendinize şu soruyu sorun: "Eğer test çalıştırıcım 200.000 test senaryosu çalıştırmak zorunda olsaydı" bu ne kadar sürerdi?

Sharding, Ticaret Federasyonu'ndaki mevcut cevaplardan biridir. Koşucunun ihtiyaç duyduğu tüm testleri paralelleştirilebilecek birkaç parçaya bölmeyi gerektirir.

Bu sayfada koşucunuzu Tradefed için nasıl parçalanabilir hale getireceğiniz açıklanmaktadır.

Uygulanacak arayüz

TF tarafından parçalanabilir olarak kabul edilecek en önemli arayüz IShardableTest'tir ve iki yöntem içerir: split(int numShard) ve split() .

Parçalamanız istenen parça sayısına bağlı olacaksa split(int numShard) uygulamanız gerekir. Aksi halde split() öğesini uygulayın.

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

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

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

Ayrıntılı örnek uygulama

Burada başvurabileceğiniz IShardableTest uygulayan örnek bir kod pasajı verilmiştir. Kodun tamamına (https://android.googlesource.com/platform/tools/tradefederation/+/refs/heads/main/test_framework/com/android/tradefed/testtype/InstalledInstrumentationsTest.java) adresinden ulaşılabilir.

/**
 * 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 buna parça parametrelerini ayarlar. Ancak bölme mantığı testten teste tamamen farklı olabilir; ve deterministik olduğu ve kolektif olarak kapsamlı alt kümeler ürettiği sürece sorun yoktur.

Bağımsızlık

Parçaların bağımsız olması gerekiyor! Koşucunuzdaki split uygulamanız tarafından oluşturulan iki parçanın birbirine bağımlılığı olmamalı veya kaynakları paylaşmamalıdır.

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

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

Testi yerel olarak parçalayın

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

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

Daha sonra 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çalı çağrılar için herhangi bir test sonucu toplama işlemi yapmadığından raporlama hizmetinizin bunu desteklediğinden emin olmanız gerekir.