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

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

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

בדף הזה מוסבר איך להגדיר את הרצת הבדיקות כך שניתן יהיה לפצל אותן ב-Tradefed.

ממשק להטמעה

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

אם ה-sharding שלכם הולך להיות תלוי במספר הרסיסים שנדרשו, כדאי להטמיע את 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-qpr2-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;
    }
    ...
}

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

Independence

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