כתיבת הרצת בדיקה מפוצלת של IremoteTest

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

פיצול הוא אחת מהתשובות הזמינות באיחוד שירותי הסחר. הוא מחייב לפצל את כל הבדיקות שדרושות לריצה לכמה מקטעי נתונים מקביל.

דף זה מתאר כיצד להפוך את ריצה לפיצול ל-TrendFed.

ממשק להטמעה

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

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

כשמריצים בדיקת TF עם פרמטרים של פיצול (sharding), --shard-count וגם --shard-index, TF עוברת באיטרציות על כל IRemoteTest כדי לחפש הטמעה של IShardableTest. אם המכשיר יימצא, תתבצע שיחה למספר split אל מקבלים אובייקט IRemoteTest חדש כדי להריץ קבוצת משנה של מקרי בדיקה שמפוצל.

מה צריך לדעת לגבי ההטמעה המפוצלת?

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