כתוב רץ מבחן של IRemoteTest

כאשר כותבים רץ מבחן, חשוב לחשוב על מדרגיות. שאלו את עצמכם, "אם רץ המבחן שלי היה צריך לרוץ מקרי מבחן של 200K" כמה זמן זה היה לוקח?

Sharding היא אחת התשובות הזמינות ב- Trade Federation. זה דורש פיצול כל הבדיקות שהרץ צריך למספר נתחים שניתן לבצע במקביל.

דף זה מתאר כיצד להפוך את הרץ שלך לניתוק עבור Tradefed.

ממשק ליישום

הממשק היחיד החשוב ביותר ליישום שייחשב ל-shardable על ידי TF הוא IShardableTest , המכיל שתי שיטות: split(int numShard) ו- split() .

אם הרסיס שלך יהיה תלוי במספר הרסיסים המבוקש, עליך ליישם split(int numShard) . אחרת, הטמיע split() .

כאשר מבוצעת פקודת בדיקת TF עם פרמטרי פיצול --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 שלך ב-runner שלך לא אמורים להיות תלויים זה בזה או לחלוק משאבים.

פיצול רסיסים צריך להיות דטרמיניסטי! זה גם חובה, בהינתן אותם תנאים, שיטת 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 אינו מבצע צבירת תוצאות בדיקה עבור קריאות חלוקות, עליך לוודא ששירות הדיווח שלך תומך בכך.