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