עם השקת התכונות הניסיוניות, יש כללי מדיניות חדשים לבדיקת הנתונים שצריך לפעול לפיהם:
- הבדיקות צריכות לכלול את ההתנהגויות של הדגל גם כשהוא מופעל וגם כשהוא מושבת.
- עליכם להשתמש במנגנונים הרשמיים כדי להגדיר את ערכי הסימונים במהלך הבדיקה.
- בדיקות xTS לא אמורות לבטל את ערכי הדגלים בבדיקות.
בקטע הבא מפורטים המנגנונים הרשמיים שבהם עליכם להשתמש כדי לעמוד בדרישות המדיניות האלה.
בדיקת הקוד שסומן
תרחיש בדיקה | המנגנון שבו נעשה שימוש |
---|---|
בדיקה מקומית כאשר ערכי הדגל משתנים לעתים קרובות | גשר לניפוי באגים ב-Android כמו שמתואר במאמר שינוי ערך של דגל בזמן ריצה |
בדיקה מקומית כשערכי הדגל לא משתנים לעיתים קרובות | קובץ ערכים של דגלים, כפי שמתואר בקטע הגדרת ערכים של דגלים להשקת תכונות |
בדיקות מקצה לקצה – כאשר ערכי הדגלים משתנים | FeatureFlagTargetPreparer כמו שמוסבר במאמר יצירת בדיקות מקצה לקצה |
בדיקת יחידה שבה משתנים ערכי הדגלים | SetFlagsRule עם @EnableFlags ו-@DisableFlags כמו שמוסבר ביצירת בדיקות יחידה (Java ו-Kotlin) או ביצירת בדיקות יחידה (C ו-C++ ). |
בדיקות מקצה לקצה או בדיקות יחידה (unit testing) שבהן ערכי הדגלים לא יכולים להשתנות | CheckFlagsRule כמו שמוסבר במאמר יצירת בדיקות מקצה לקצה או בדיקות יחידה שבהן ערכי הדגלים לא משתנים |
יצירת בדיקות מקצה לקצה
ב-AOSP יש קלאס שנקרא FeatureFlagTargetPreparer
שמאפשר בדיקה מקצה לקצה במכשיר. הכיתה הזו מקבלת כקלט ערכי דגלים שהוגדרו מראש, מגדירה את הדגלים האלה בתצורת המכשירים לפני ביצוע הבדיקה ומחזירה את הדגלים אחרי הביצוע.
אפשר להחיל את הפונקציונליות של הכיתה FeatureFlagTargetPreparer
ברמת מודול הבדיקה וברמת הגדרת הבדיקה.
החלת FeatureflagTargetPreparer בתצורה של מודול בדיקה
כדי להחיל את FeatureFlagTargetPreparer
על הגדרה של מודול בדיקה, צריך לכלול את FeatureFlagTargetPreparer
ואת ערכי הדגלים בקובץ התצורה של מודול הבדיקה AndroidTest.xml
:
<target_preparer class="com.android.tradefed.targetprep.FeatureFlagTargetPreparer">
<option name="flag-value"
value="permissions/com.android.permission.flags.device_aware_permission_grant=true"/>
<option name="flag-value"
value="virtual_devices/android.companion.virtual.flags.stream_permissions=true"/>
</target_preparer>
איפה:
- הערך
target.preparer class
תמיד מוגדר ל-com.android.tradefed.targetprep.FeatureFlagTargetPreparer
. option
הוא שינוי הדגל, כאשרname
תמיד מוגדר לערךflag-value
ו-value
מוגדר לערךnamespace/aconfigPackage.flagName=true|false
.
יצירת מודולים של בדיקות עם פרמטרים על סמך מצבי דגלים
כדי ליצור מודולים לבדיקה עם פרמטרים על סמך מצבי סימון:
כוללים את
FeatureFlagTargetPreparer
בקובץ התצורה של מודול הבדיקהAndroidTest.xml
:<target_preparer class="com.android.tradefed.targetprep.FeatureFlagTargetPreparer" >
מציינים אפשרויות של ערך דגל בקטע
test_module_config
בקובץ build מסוגAndroid.bp
:android_test { name: "MyTest" ... } test_module_config { name: "MyTestWithMyFlagEnabled", base: "MyTest", ... options: [ {name: "flag-value", value: "telephony/com.android.internal.telephony.flags.oem_enabled_satellite_flag=true"}, ], } test_module_config { name: "MyTestWithMyFlagDisabled", base: "MyTest", ... options: [ {name: "flag-value", value: "telephony/com.android.internal.telephony.flags.carrier_enabled_satellite_flag=true"}, ], }
השדה
options
מכיל את שינויי הדגל כאשרname
מוגדר תמיד ל-flag-value
ו-value
מוגדר ל-namespace/aconfigPackage.flagName=true|false
.
ליצור בדיקות יחידה (Java ו-Kotlin)
בקטע הזה מתוארת הגישה לשינוי ערכי דגלי הגדרה ברמת המחלקה וה-method (לכל בדיקה) בבדיקות Java ו-Kotlin.
כדי לכתוב בדיקות יחידה אוטומטיות ב-codebase גדול עם מספר גדול של דגלים, מבצעים את הפעולות הבאות:
- משתמשים במחלקה
SetFlagsRule
עם ההערות@EnableFlags
ו-@DisableFlags
כדי לבדוק את כל הסתעפויות הקוד. - כדאי להשתמש בשיטה
SetFlagsRule.ClassRule
כדי להימנע מבאגים נפוצים בבדיקה. - תוכלו להשתמש ב-
FlagsParameterization
כדי לבדוק את הכיתות בקבוצה רחבה של הגדרות דגל.
בדיקת כל הסתעפויות הקוד
בפרויקטים שמשתמשים במחלקה הסטטית כדי לגשת בדגלים, המחלקה המסייעת SetFlagsRule
זמינה כדי לשנות את ערכי הדגלים. בקטע הקוד הבא מוסבר איך לכלול את SetFlagsRule
ולהפעיל כמה דגלים בו-זמנית:
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import com.example.android.aconfig.demo.flags.Flags;
...
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@Test
@EnableFlags({Flags.FLAG_FLAG_FOO, Flags.FLAG_FLAG_BAR})
public void test_flag_foo_and_flag_bar_turned_on() {
...
}
איפה:
@Rule
הוא הערה שמשמשת להוספת התלות של דגל-JUnit של המחלקהSetFlagsRule
.SetFlagsRule
היא כיתת עזר שמיועדת לשינוי ערכים של דגלים. במאמר ערכי ברירת מחדל של המכשיר מוסבר איךSetFlagsRule
קובע את ערכי ברירת המחדל.@EnableFlags
הוא הערה שמקבלת מספר שרירותי של שמות דגלים. כשמשביתים דגלים, משתמשים ב-@DisableFlags
. אפשר להחיל את ההערות האלה על שיטה או על כיתה.
מגדירים ערכי דגל לכל תהליך הבדיקה, החל מ-SetFlagsRule
, שלפני כל שיטת הגדרה עם הערות עם @Before
בבדיקה. ערכי הדגלים חוזרים למצבם הקודם בסיום SetFlagsRule
, כלומר אחרי כל שיטות ההגדרה עם הערות @After
.
מוודאים שהדגלים מוגדרים בצורה נכונה
כפי שציינו קודם, SetFlagsRule
משמש עם ההערה @Rule
של ה-JUnit, והמשמעות היא ש-SetFlagsRule
לא יכול לוודא שהדגלים מוגדרים נכון במהלך ה-constructor של מחלקת הבדיקה, או בשיטות אחרות עם הערות @BeforeClass
או @AfterClass
.
כדי לוודא שהאביזר לבדיקה נוצר עם ערך הכיתה הנכון, צריך להשתמש ב-method SetFlagsRule.ClassRule
כדי שהאביזר לא נוצר עד ש-method ההגדרה מתויג ב-@Before
:
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import com.example.android.aconfig.demo.flags.Flags;
class ExampleTest {
@ClassRule public static final SetFlagsRule.ClassRule mClassRule = new SetFlagsRule.ClassRule();
@Rule public final SetFlagsRule mSetFlagsRule = mClassRule.createSetFlagsRule();
private DemoClass underTest = new DemoClass();
@Test
@EnableFlags(Flags.FLAG_FLAG_FOO)
public void test_flag_foo_turned_on() {
...
}
}
הוספת כלל הכיתה SetFlagsRule.ClassRule
גורמת ל-test_flag_foo_turned_on
להיכשל לפני הריצה, כש-FLAG_FLAG_FOO
נקרא על ידי ה-constructor של DemoClass
.
אם צריך להפעיל את הדגל בכיתה כולה, מעבירים את ההערה @EnableFlags
לרמת הכיתה (לפני הצהרת הכיתה). העברת ההערה לרמת המחלקה מאפשרת ל-SetFlagsRule.ClassRule
לוודא שהדגל מוגדר כראוי במהלך ה-constructor של מחלקה הבדיקה, או בכל שיטה של @BeforeClass
או @AfterClass
עם הערות.
הרצת בדיקות בכמה הגדרות דגלים
מכיוון שאפשר להגדיר ערכי דגלים לכל בדיקה בנפרד, אפשר גם להשתמש בפרמטרים כדי להריץ בדיקות במספר הגדרות של דגלים:
...
import com.example.android.aconfig.demo.flags.Flags;
...
@RunWith(ParameterizedAndroidJunit4::class)
class FooBarTest {
@Parameters(name = "{0}")
public static List<FlagsParameterization> getParams() {
return FlagsParameterization.allCombinationsOf(Flags.FLAG_FOO, Flags.FLAG_BAR);
}
@Rule
public SetFlagsRule mSetFlagsRule;
public FooBarTest(FlagsParameterization flags) {
mSetFlagsRule = new SetFlagsRule(flags);
}
@Test public void fooLogic() {...}
@DisableFlags(Flags.FLAG_BAR)
@Test public void legacyBarLogic() {...}
@EnableFlags(Flags.FLAG_BAR)
@Test public void newBarLogic() {...}
}
הערה: עם SetFlagsRule
, אבל בלי פרמטרים, המחלקה הזו תריץ שלושה בדיקות (fooLogic
, legacyBarLogic
ו-newBarLogic
). ה-method fooLogic
פועלת עם הערכים של FLAG_FOO
ו-FLAG_BAR
שמוגדרים במכשיר.
כשמוסיפים פרמטרים, השיטה FlagsParameterization.allCombinationsOf
יוצרת את כל השילובים האפשריים של הדגלים FLAG_FOO
ו-FLAG_BAR
:
FLAG_FOO
הואtrue
ו-FLAG_BAR
הואtrue
FLAG_FOO
הואtrue
ו-FLAG_BAR
הואfalse
FLAG_FOO
הואfalse
ו-FLAG_BAR
הואtrue
- הערך של
FLAG_FOO
הוא false והערך שלFLAG_BAR
הואfalse
במקום לשנות את ערכי הדגלים ישירות, הערות @DisableFlags
ו-@EnableFlags
משנות את ערכי הדגלים על סמך תנאי הפרמטרים. לדוגמה, הפקודה legacyBarLogic
פועלת רק כשהפקודה FLAG_BAR
מושבתת, וזה קורה בשניים מתוך ארבעת שילובי הדגלים. המערכת מדלגת על ה-legacyBarLogic
בשביל שני השילובים האחרים.
יש שתי שיטות ליצירת הפרמטרים של הדגלים:
FlagsParameterization.allCombinationsOf(String...)
רץ 2^n הפעלות של כל בדיקה. לדוגמה, דגל אחד מפעיל פי 2 בדיקות או ארבעה דגלים מריצים בדיקות 16x.FlagsParameterization.progressionOf(String...)
מריץ n+1 הפעלות בכל בדיקה. לדוגמה, דגל אחד מפעיל 2x בדיקות וארבעה דגלים מפעילים 5x דגלים.
יצירת בדיקות יחידה (C ו-C++)
AOSP כולל פקודות מאקרו של ערכי דגלים לבדיקות C ו-C++ שנכתבו במסגרת GoogleTest.
במקור הבדיקה, צריך לכלול את הגדרות המאקרו ואת הספריות שנוצרו על ידי aconfig:
#include <flag_macros.h> #include "android_cts_flags.h"
במקור הבדיקה, במקום להשתמש בפקודות מאקרו
TEST
ו-TESTF
למקרי הבדיקה, משתמשים ב-TEST_WITH_FLAGS
וב-TEST_F_WITH_FLAGS
:#define TEST_NS android::cts::flags::tests ... TEST_F_WITH_FLAGS( TestFWithFlagsTest, requies_disabled_flag_enabled_skip, REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(TEST_NS, readwrite_enabled_flag)) ) { TestFail(); } ... TEST_F_WITH_FLAGS( TestFWithFlagsTest, multi_flags_for_same_state_skip, REQUIRES_FLAGS_ENABLED( ACONFIG_FLAG(TEST_NS, readwrite_enabled_flag), LEGACY_FLAG(aconfig_flags.cts, TEST_NS, readwrite_disabled_flag) ) ) { TestFail(); } ... TEST_WITH_FLAGS( TestWithFlagsTest, requies_disabled_flag_enabled_skip, REQUIRES_FLAGS_DISABLED( LEGACY_FLAG(aconfig_flags.cts, TEST_NS, readwrite_enabled_flag)) ) { FAIL(); } ... TEST_WITH_FLAGS( TestWithFlagsTest, requies_enabled_flag_enabled_executed, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(TEST_NS, readwrite_enabled_flag)) ) { TestWithFlagsTestHelper::executed_tests.insert( "requies_enabled_flag_enabled_executed"); }
איפה:
- בפקודות המאקרו
TEST_WITH_FLAGS
ו-TEST_F_WITH_FLAGS
נעשה שימוש במקום בפקודות המאקרוTEST
ו-TEST_F
. REQUIRES_FLAGS_ENABLED
מגדיר קבוצה של דגלים להשקת תכונות שחייבים לעמוד בתנאי שהופעל. אפשר לכתוב את הדגלים האלה במאקרו שלACONFIG_FLAG
אוLEGACY_FLAG
.REQUIRES_FLAGS_DISABLED
מגדיר קבוצה של דגלים של תכונות שצריכים לעמוד בתנאים של השבתה. אפשר לכתוב את הדגלים האלה בפקודות מאקרוACONFIG_FLAG
אוLEGACY_FLAG
.ACONFIG_FLAG (TEST_NS, readwrite_enabled_flag)
הוא מאקרו שמשמש לדגלים שמוגדרים בקובצי aconfig. המאקרו הזה מקבל מרחב שמות (TEST_NS
) ושם דגל (readwrite_enabled_flag
).LEGACY_FLAG(aconfig_flags.cts, TEST_NS, readwrite_disabled_flag)
הוא מאקרו שמשמש לדגלים שמוגדרים בהגדרות המכשיר כברירת מחדל.
- בפקודות המאקרו
בקובץ ה-build של
Android.bp
, מוסיפים את הספריות שנוצרות על ידי הגדרה ואת ספריות המאקרו הרלוונטיות כתלות בבדיקה:cc_test { name: "FlagMacrosTests", srcs: ["src/FlagMacrosTests.cpp"], static_libs: [ "libgtest", "libflagtest", "my_aconfig_lib", ], shared_libs: [ "libbase", "server_configurable_flags", ], test_suites: ["general-tests"], ... }
מריצים את הבדיקות באופן מקומי באמצעות הפקודה הבאה:
atest FlagMacrosTests
אם הדגל
my_namespace.android.myflag.tests.my_flag
מושבת, תוצאת הבדיקה היא:[1/2] MyTest#test1: IGNORED (0ms) [2/2] MyTestF#test2: PASSED (0ms)
אם הדגל
my_namespace.android.myflag.tests.my_flag
מופעל, תוצאת הבדיקה היא:[1/2] MyTest#test1: PASSED (0ms) [2/2] MyTestF#test2: IGNORED (0ms)
יצירת בדיקות מקצה לקצה או בדיקות יחידה כאשר ערכי הדגלים לא משתנים
במקרי בדיקה שבהם אי אפשר לבטל דגלים ואפשר לסנן בדיקות רק אם הם מבוססים על מצב הדגל הנוכחי, אפשר להשתמש בכלל CheckFlagsRule
עם ההערות RequiresFlagsEnabled
ו-RequiresFlagsDisabled
.
בשלבים הבאים מוסבר איך ליצור ולהריץ בדיקה מקצה לקצה או בדיקת יחידה שבה לא ניתן לשנות את ערכי הדגלים:
בקוד הבדיקה, משתמשים ב-
CheckFlagsRule
כדי להחיל סינון של בדיקות. כמו כן, השתמשו בהערותRequiresFlagsEnabled
ו-RequiredFlagsDisabled
ב-Java כדי לציין את דרישות הדגל לבדיקה.בבדיקה בצד המכשיר נעשה שימוש במחלקה
DeviceFlagsValueProvider
:@RunWith(JUnit4.class) public final class FlagAnnotationTest { @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); @Test @RequiresFlagsEnabled(Flags.FLAG_FLAG_NAME_1) public void test1() {} @Test @RequiresFlagsDisabled(Flags.FLAG_FLAG_NAME_1) public void test2() {} }
הבדיקה בצד המארח משתמשת בכיתה
HostFlagsValueProvider
:@RunWith(DeviceJUnit4ClassRunner.class) public final class FlagAnnotationTest extends BaseHostJUnit4Test { @Rule public final CheckFlagsRule mCheckFlagsRule = HostFlagsValueProvider.createCheckFlagsRule(this::getDevice); @Test @RequiresFlagsEnabled(Flags.FLAG_FLAG_NAME_1) public void test1() {} @Test @RequiresFlagsDisabled(Flags.FLAG_FLAG_NAME_1) public void test2() {} }
מוסיפים את
jflag-unit
ואת הספריות שנוצרו על ידי aconfig לקטעstatic_libs
בקובץ ה-build של הבדיקה:android_test { name: "FlagAnnotationTests", srcs: ["*.java"], static_libs: [ "androidx.test.rules", "my_aconfig_lib", "flag-junit", "platform-test-annotations", ], test_suites: ["general-tests"], }
כדי להריץ את הבדיקה באופן מקומי, משתמשים בפקודה הבאה:
atest FlagAnnotationTests
אם הדגל
Flags.FLAG_FLAG_NAME_1
מושבת, תוצאת הבדיקה היא:[1/2] com.cts.flags.FlagAnnotationTest#test1: ASSUMPTION_FAILED (10ms) [2/2] com.cts.flags.FlagAnnotationTest#test2: PASSED (2ms)
אחרת, תוצאת הבדיקה תהיה:
[1/2] com.cts.flags.FlagAnnotationTest#test1: PASSED (2ms) [2/2] com.cts.flags.FlagAnnotationTest#test2: ASSUMPTION_FAILED (10ms)
ערכי ברירת המחדל של המכשיר
המשתנה SetFlagsRule
שמאותחל משתמש בערכים של הדגלים מהמכשיר. אם לא משנים את ערך הדגל במכשיר, למשל באמצעות adb, ערך ברירת המחדל זהה להגדרת הגרסה של ה-build. אם הערך במכשיר השתנה, הערך החדש ישמש כערך ברירת המחדל ב-SetFlagsRule
.
אם אותה בדיקה תבוצע בהגדרות שונות של גרסאות, ערך הדגלים שלא הוגדרו במפורש עם SetFlagsRule
עשוי להשתנות.
אחרי כל בדיקה, SetFlagsRule
משחזר את המכונה FeatureFlags
ב-Flags
ל-FeatureFlagsImpl
המקורי שלה, כך שלא יהיו לה תופעות לוואי על שיטות בדיקה וסיווגים אחרים.