Menulis runner pengujian IRemoteTest yang di-shard

Saat menulis peluncur pengujian, penting untuk memikirkan skalabilitas. Tanyakan pada diri Anda, "jika pelaksana pengujian saya harus menjalankan 200 ribu kasus pengujian", berapa lama waktu yang dibutuhkan?

Sharding adalah salah satu jawaban yang tersedia di Trade Federation. Hal ini memerlukan pemisahan semua pengujian yang diperlukan peluncur menjadi beberapa bagian yang dapat diparalelkan.

Halaman ini menjelaskan cara membuat runner Anda dapat di-shard untuk Tradefed.

Antarmuka yang akan diimplementasikan

Antarmuka terpenting yang harus diterapkan agar dianggap dapat di-shard oleh TF adalah IShardableTest, yang berisi dua metode: split(int numShard) dan split().

Jika sharding Anda akan bergantung pada jumlah shard yang diminta, Anda harus menerapkan split(int numShard). Jika tidak, terapkan split().

Saat perintah pengujian TF dijalankan dengan parameter sharding --shard-count dan --shard-index, TF akan melakukan iterasi di semua IRemoteTest untuk mencari yang menerapkan IShardableTest. Jika ditemukan, metode ini akan memanggil split untuk mendapatkan objek IRemoteTest baru untuk menjalankan subset kasus pengujian untuk shard tertentu.

Apa yang harus saya ketahui tentang penerapan pemisahan?

  • Pelari Anda mungkin melakukan sharding hanya pada beberapa kondisi; dalam hal ini, tampilkan null jika Anda tidak melakukan sharding.
  • Coba bagi sebanyak yang masuk akal: bagi runner Anda menjadi unit eksekusi yang masuk akal. Hal ini sangat bergantung pada pelari Anda. Misalnya: HostTest di-shard di tingkat Class, setiap class pengujian ditempatkan di shard terpisah.
  • Jika masuk akal, tambahkan beberapa opsi untuk mengontrol sharding. Misalnya: AndroidJUnitTest memiliki ajur-max-shard untuk menentukan jumlah maksimum pecahan yang dapat dibagi, terlepas dari jumlah yang diminta.

Contoh penerapan mendetail

Berikut adalah contoh cuplikan kode yang mengimplementasikan IShardableTest yang dapat Anda rujuk. Kode lengkap tersedia di (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;
    }
    ...
}

Contoh ini hanya membuat instance baru dari dirinya sendiri dan menetapkan parameter shard ke instance tersebut. Namun, logika pemisahan dapat sangat berbeda dari satu pengujian ke pengujian lainnya; dan selama bersifat deterministik dan menghasilkan subset yang secara kolektif lengkap, tidak masalah.

Kemerdekaan

Shard harus independen. Dua shard yang dibuat oleh penerapan split di runner Anda tidak boleh memiliki dependensi satu sama lain atau berbagi resource.

Pemisahan shard harus bersifat deterministik. Hal ini juga wajib dilakukan, mengingat kondisi yang sama, metode split Anda harus selalu menampilkan daftar shard yang sama persis dalam urutan yang sama.

CATATAN: Karena setiap shard dapat berjalan di instance TF yang berbeda, sangat penting untuk memastikan logika split menghasilkan subset yang saling eksklusif dan secara kolektif lengkap dengan cara yang deterministik.

Membagi pengujian secara lokal

Untuk memecah pengujian di TF lokal, Anda cukup menambahkan opsi --shard-count ke command line.

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

Kemudian, TF akan otomatis membuat perintah untuk setiap shard dan menjalankannya.

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)

Agregasi hasil pengujian

Karena TF tidak melakukan agregasi hasil pengujian untuk pemanggilan yang di-shard, Anda harus memastikan layanan pelaporan Anda mendukungnya.