یک آزمون اجراکننده IRemoteTest خرد شده بنویسید

هنگام نوشتن یک تست رانر، مهم است که به مقیاس‌پذیری فکر کنید. از خود بپرسید، «اگر تست رانر من مجبور باشد ۲۰۰ هزار مورد تست را اجرا کند»، چقدر طول می‌کشد؟

شاردینگ یکی از پاسخ‌های موجود در فدراسیون تجارت است. این روش مستلزم تقسیم تمام تست‌هایی است که اجراکننده به آنها نیاز دارد و می‌توان آنها را موازی‌سازی کرد.

این صفحه نحوه‌ی شاردبل کردن دونده‌ی شما برای Tradefed را شرح می‌دهد.

رابط برای پیاده‌سازی

مهم‌ترین رابطی که باید پیاده‌سازی شود تا توسط TF قابل شارد شدن در نظر گرفته شود، IShardableTest است که شامل دو متد است: split(int numShard) و split() .

اگر قرار است شاردینگ شما به تعداد شاردهای درخواستی بستگی داشته باشد، باید split(int numShard) را پیاده‌سازی کنید. در غیر این صورت، split() را پیاده‌سازی کنید.

وقتی یک دستور تست TF با پارامترهای شاردینگ --shard-count و --shard-index اجرا می‌شود، TF در تمام IRemoteTest جستجو می‌کند تا مواردی را که IShardableTest پیاده‌سازی می‌کنند، پیدا کند. در صورت یافتن، split فراخوانی می‌کند تا یک شیء IRemoteTest جدید برای اجرای زیرمجموعه‌ای از موارد تست برای یک شارد خاص دریافت کند.

در مورد پیاده‌سازی split چه چیزهایی باید بدانم؟

  • شما می‌توانید فقط تحت برخی شرایط، عمل shard را انجام دهید؛ در این صورت، در صورتی که shard انجام نداده باشید، null را برمی‌گردانید.
  • سعی کنید تا جایی که منطقی است، تقسیم‌بندی کنید: runner خود را به واحد اجرایی که برای آن منطقی است تقسیم کنید. این واقعاً به runner شما بستگی دارد. به عنوان مثال: HostTest در سطح کلاس shard شده است، هر کلاس تست در یک shard جداگانه قرار می‌گیرد.
  • اگر منطقی است، چند گزینه برای کنترل کمی تقسیم‌بندی اضافه کنید. برای مثال: AndroidJUnitTest یک ajur-max-shard دارد تا حداکثر تعداد shardهایی را که می‌تواند تقسیم کند، صرف نظر از تعداد درخواستی، مشخص کند.

پیاده‌سازی مثال با جزئیات

در اینجا یک قطعه کد نمونه برای پیاده‌سازی IShardableTest ارائه شده است که می‌توانید به آن مراجعه کنید. کد کامل در آدرس (https://android.googlesource.com/platform/tools/tradefederation/+/refs/heads/android16-qpr1-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;
    }
    ...
}

این مثال به سادگی یک نمونه جدید از خودش ایجاد می‌کند و پارامترهای shard را برای آن تنظیم می‌کند. با این حال، منطق تقسیم می‌تواند از آزمایشی به آزمایش دیگر کاملاً متفاوت باشد؛ و تا زمانی که قطعی باشد و زیرمجموعه‌های جامعی را به صورت جمعی ارائه دهد، اشکالی ندارد.

استقلال

Shardها باید مستقل باشند! دو Shard که با پیاده‌سازی split در runner ایجاد می‌شوند، نباید به یکدیگر وابستگی داشته باشند یا منابع را به اشتراک بگذارند.

تقسیم‌بندی Shardها باید قطعی باشد! این مورد نیز اجباری است، با توجه به شرایط یکسان، متد split شما باید همیشه دقیقاً همان لیست Shardها را با همان ترتیب برگرداند.

توجه: از آنجایی که هر شارد می‌تواند روی نمونه‌های مختلف TF اجرا شود، بسیار مهم است که اطمینان حاصل شود منطق split ، زیرمجموعه‌هایی را ارائه می‌دهد که به طور متقابل منحصر به فرد و به طور جمعی به شیوه‌ای قطعی جامع هستند.

یک تست را به صورت محلی خرد کنید

برای خرد کردن یک تست روی یک TF محلی، می‌توانید به سادگی گزینه --shard-count را به خط فرمان اضافه کنید.

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

سپس TF به طور خودکار دستوراتی را برای هر Shard ایجاد کرده و آنها را اجرا می‌کند.

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 هیچ تجمیع نتایج آزمایشی برای فراخوانی‌های تکه‌تکه‌شده انجام نمی‌دهد، باید مطمئن شوید که سرویس گزارش‌دهی شما از آن پشتیبانی می‌کند.