כתיבה של מפעיל בדיקות 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.
  • כדאי לפצל את הרץ כמה שיותר: לפצל את הרץ ליחידות של ביצוע שמתאימות לו. זה באמת תלוי ב-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;
    }
    ...
}

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

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