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

هنگام نوشتن یک تست دونده، مهم است که به مقیاس پذیری فکر کنید. از خود بپرسید، "اگر دونده آزمایشی من مجبور بود 200 هزار مورد تست را اجرا کند" چقدر طول می کشد؟

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

این صفحه نحوه ساخت رانر خود را برای Tradefed توضیح می دهد.

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

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

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

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

در مورد اجرای اسپلیت چه چیزی باید بدانم؟

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

اجرای نمونه دقیق

در اینجا یک نمونه کد کد پیاده سازی IShardableTest است که می توانید به آن مراجعه کنید. کد کامل در (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;
    }
    ...
}

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

استقلال

خرده پاها باید مستقل باشند! دو قطعه ایجاد شده توسط اجرای split در رانر شما نباید به یکدیگر وابستگی داشته باشند یا منابع را به اشتراک بگذارند.

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

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

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

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

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

سپس TF به طور خودکار دستورات را برای هر قطعه ارسال می کند و آنها را اجرا می کند.

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