כתיבה של מפעיל בדיקות IRemoteTest מפוצל

כשכותבים מפעיל בדיקות, חשוב להביא בחשבון את יכולת ההתאמה לעומס. כדאי לשאול את עצמכם: "אם הכלי להרצת הבדיקות שלי יצטרך להריץ 200,000 תרחישי בדיקה, כמה זמן זה ייקח?"

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

בדף הזה מוסבר איך להפוך את ה-runner לניתן לחלוקה לחלקים ב-Tradefed.

ממשק להטמעה

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

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

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

מה חשוב לדעת לגבי הטמעת הפיצול?

  • ה-runner יכול לפצל לפי תנאים מסוימים בלבד. במקרה כזה, צריך להחזיר את הערך null כשלא בוצע פיצול.
  • נסו לפצל כמה שאפשר, אבל בצורה הגיונית: עדיף לפצל את ה-runner ליחידות ביצוע הגיוניות. זה תלוי בגורם שמריץ את הבדיקה. לדוגמה: HostTest מחולק למקטעים ברמת הכיתה, כל כיתה של בדיקות מועברת למקטע נפרד.
  • אם זה הגיוני, מוסיפים כמה אפשרויות כדי לשלוט קצת בחלוקה לפלחים. לדוגמה: ל-AndroidJUnitTest יש את ajur-max-shard כדי לציין את המספר המקסימלי של פלחים שאפשר לפצל אותו אליהם, ללא קשר למספר המבוקש.

דוגמה מפורטת להטמעה

הנה קטע קוד לדוגמה שמטמיע את IShardableTest. הקוד המלא זמין בכתובת (https://android.googlesource.com/platform/tools/tradefederation/+/refs/heads/android16-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;
    }
    ...
}

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

עצמאות

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

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