Menulis runner pengujian IRemoteTest yang di-sharding

Saat menulis runner pengujian, penting untuk mempertimbangkan skalabilitas. Tanyakan diri Anda, "jika runner pengujian saya harus menjalankan 200 ribu kasus pengujian", berapa lama waktu yang diperlukan?

Sharding adalah salah satu jawaban yang tersedia di Trade Federation. Hal ini memerlukan pemisahan semua pengujian yang diperlukan runner 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 akan bergantung pada jumlah shard yang diminta, Anda harus menerapkan split(int numShard). Jika tidak, terapkan split().

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

Apa yang harus saya ketahui tentang penerapan pemisahan?

  • Runner Anda mungkin melakukan shard hanya berdasarkan beberapa kondisi; dalam hal ini, tampilkan null saat Anda tidak melakukan shard.
  • Cobalah untuk membagi sebanyak mungkin: bagi runner Anda menjadi unit eksekusi yang sesuai. Hal ini sangat bergantung pada runner Anda. Misalnya: HostTest di-shard di tingkat Class, setiap class pengujian ditempatkan di shard terpisah.
  • Jika memungkinkan, tambahkan beberapa opsi untuk sedikit mengontrol sharding. Misalnya: AndroidJUnitTest memiliki ajur-max-shard untuk menentukan jumlah maksimum shard yang dapat dibagi, terlepas dari jumlah yang diminta.

Contoh penerapan mendetail

Berikut adalah contoh cuplikan kode yang mengimplementasikan IShardableTest yang dapat Anda referensikan. Kode lengkapnya tersedia di (https://android.googlesource.com/platform/tools/tradefederation/+/refs/heads/main/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 dan menetapkan parameter shard ke instance tersebut. Namun, logika pemisahan dapat sangat berbeda dari pengujian ke pengujian; dan selama logika tersebut bersifat determenistik dan menghasilkan subset yang menyeluruh secara kolektif, hal tersebut tidak masalah.

Kemerdekaan

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

Pemisahan shard harus bersifat determenistik. Ini juga wajib, dengan kondisi yang sama, metode split 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 deterministik.

Membagi pengujian secara lokal

Untuk membuat shard 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 memunculkan 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 shard, Anda harus memastikan layanan pelaporan mendukungnya.