1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.textclassifier.downloader; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import android.view.textclassifier.TextClassification; 22 import android.view.textclassifier.TextClassification.Request; 23 import androidx.test.filters.FlakyTest; 24 import com.android.textclassifier.testing.ExtServicesTextClassifierRule; 25 import org.junit.After; 26 import org.junit.Before; 27 import org.junit.Rule; 28 import org.junit.Test; 29 import org.junit.runner.RunWith; 30 import org.junit.runners.JUnit4; 31 32 @RunWith(JUnit4.class) 33 public class ModelDownloaderIntegrationTest { 34 private static final String TAG = "ModelDownloaderTest"; 35 private static final String EXPERIMENTAL_EN_ANNOTATOR_MANIFEST_URL = 36 "https://www.gstatic.com/android/text_classifier/r/experimental/v999999999/en.fb.manifest"; 37 private static final String EXPERIMENTAL_EN_TAG = "en_v999999999"; 38 private static final String V804_EN_ANNOTATOR_MANIFEST_URL = 39 "https://www.gstatic.com/android/text_classifier/r/v804/en.fb.manifest"; 40 private static final String V804_RU_ANNOTATOR_MANIFEST_URL = 41 "https://www.gstatic.com/android/text_classifier/r/v804/ru.fb.manifest"; 42 private static final String V804_EN_TAG = "en_v804"; 43 private static final String V804_RU_TAG = "ru_v804"; 44 private static final String FACTORY_MODEL_TAG = "*"; 45 private static final int ASSERT_MAX_ATTEMPTS = 20; 46 private static final int ASSERT_SLEEP_BEFORE_RETRY_MS = 1000; 47 48 @Rule 49 public final ExtServicesTextClassifierRule extServicesTextClassifierRule = 50 new ExtServicesTextClassifierRule(); 51 52 @Before setup()53 public void setup() throws Exception { 54 extServicesTextClassifierRule.addDeviceConfigOverride("config_updater_model_enabled", "false"); 55 extServicesTextClassifierRule.addDeviceConfigOverride("model_download_manager_enabled", "true"); 56 extServicesTextClassifierRule.addDeviceConfigOverride( 57 "model_download_backoff_delay_in_millis", "5"); 58 extServicesTextClassifierRule.addDeviceConfigOverride("testing_locale_list_override", "en-US"); 59 extServicesTextClassifierRule.overrideDeviceConfig(); 60 61 extServicesTextClassifierRule.enableVerboseLogging(); 62 // Verbose logging only takes effect after restarting ExtServices 63 extServicesTextClassifierRule.forceStopExtServices(); 64 } 65 66 @After tearDown()67 public void tearDown() throws Exception { 68 // This is to reset logging/locale_override for ExtServices. 69 extServicesTextClassifierRule.forceStopExtServices(); 70 } 71 72 @Test 73 @FlakyTest(bugId = 284901878) smokeTest()74 public void smokeTest() throws Exception { 75 extServicesTextClassifierRule.addDeviceConfigOverride( 76 "manifest_url_annotator_en", V804_EN_ANNOTATOR_MANIFEST_URL); 77 78 assertWithRetries(() -> verifyActiveEnglishModel(V804_EN_TAG)); 79 } 80 81 @Test 82 @FlakyTest(bugId = 284901878) downgradeModel()83 public void downgradeModel() throws Exception { 84 // Download an experimental model. 85 extServicesTextClassifierRule.addDeviceConfigOverride( 86 "manifest_url_annotator_en", EXPERIMENTAL_EN_ANNOTATOR_MANIFEST_URL); 87 88 assertWithRetries(() -> verifyActiveEnglishModel(EXPERIMENTAL_EN_TAG)); 89 90 // Downgrade to an older model. 91 extServicesTextClassifierRule.addDeviceConfigOverride( 92 "manifest_url_annotator_en", V804_EN_ANNOTATOR_MANIFEST_URL); 93 94 assertWithRetries(() -> verifyActiveEnglishModel(V804_EN_TAG)); 95 } 96 97 @Test 98 @FlakyTest(bugId = 284901878) upgradeModel()99 public void upgradeModel() throws Exception { 100 // Download a model. 101 extServicesTextClassifierRule.addDeviceConfigOverride( 102 "manifest_url_annotator_en", V804_EN_ANNOTATOR_MANIFEST_URL); 103 104 assertWithRetries(() -> verifyActiveEnglishModel(V804_EN_TAG)); 105 106 // Upgrade to an experimental model. 107 extServicesTextClassifierRule.addDeviceConfigOverride( 108 "manifest_url_annotator_en", EXPERIMENTAL_EN_ANNOTATOR_MANIFEST_URL); 109 110 assertWithRetries(() -> verifyActiveEnglishModel(EXPERIMENTAL_EN_TAG)); 111 } 112 113 @Test 114 @FlakyTest(bugId = 284901878) clearFlag()115 public void clearFlag() throws Exception { 116 // Download a new model. 117 extServicesTextClassifierRule.addDeviceConfigOverride( 118 "manifest_url_annotator_en", EXPERIMENTAL_EN_ANNOTATOR_MANIFEST_URL); 119 120 assertWithRetries(() -> verifyActiveEnglishModel(EXPERIMENTAL_EN_TAG)); 121 122 // Revert the flag. 123 extServicesTextClassifierRule.addDeviceConfigOverride("manifest_url_annotator_en", ""); 124 // Fallback to use the universal model. 125 assertWithRetries( 126 () -> verifyActiveModel(/* text= */ "abc", /* expectedVersion= */ FACTORY_MODEL_TAG)); 127 } 128 129 @Test 130 @FlakyTest(bugId = 267344737) modelsForMultipleLanguagesDownloaded()131 public void modelsForMultipleLanguagesDownloaded() throws Exception { 132 extServicesTextClassifierRule.addDeviceConfigOverride("multi_language_support_enabled", "true"); 133 extServicesTextClassifierRule.addDeviceConfigOverride( 134 "testing_locale_list_override", "en-US,ru-RU"); 135 136 // download en model 137 extServicesTextClassifierRule.addDeviceConfigOverride( 138 "manifest_url_annotator_en", EXPERIMENTAL_EN_ANNOTATOR_MANIFEST_URL); 139 140 // download ru model 141 extServicesTextClassifierRule.addDeviceConfigOverride( 142 "manifest_url_annotator_ru", V804_RU_ANNOTATOR_MANIFEST_URL); 143 assertWithRetries(() -> verifyActiveEnglishModel(EXPERIMENTAL_EN_TAG)); 144 145 assertWithRetries(this::verifyActiveRussianModel); 146 147 assertWithRetries( 148 () -> verifyActiveModel(/* text= */ "français", /* expectedVersion= */ FACTORY_MODEL_TAG)); 149 } 150 assertWithRetries(Runnable assertRunnable)151 private void assertWithRetries(Runnable assertRunnable) throws Exception { 152 for (int i = 0; i < ASSERT_MAX_ATTEMPTS; i++) { 153 try { 154 extServicesTextClassifierRule.overrideDeviceConfig(); 155 assertRunnable.run(); 156 break; // success. Bail out. 157 } catch (AssertionError ex) { 158 if (i == ASSERT_MAX_ATTEMPTS - 1) { // last attempt, give up. 159 extServicesTextClassifierRule.dumpDefaultTextClassifierService(); 160 throw ex; 161 } else { 162 Thread.sleep(ASSERT_SLEEP_BEFORE_RETRY_MS); 163 } 164 } catch (Exception unknownException) { 165 throw unknownException; 166 } 167 } 168 } 169 verifyActiveModel(String text, String expectedVersion)170 private void verifyActiveModel(String text, String expectedVersion) { 171 TextClassification textClassification = 172 extServicesTextClassifierRule 173 .getTextClassifier() 174 .classifyText(new Request.Builder(text, 0, text.length()).build()); 175 // The result id contains the name of the just used model. 176 assertThat(textClassification.getId()).contains(expectedVersion); 177 } 178 verifyActiveEnglishModel(String expectedVersion)179 private void verifyActiveEnglishModel(String expectedVersion) { 180 verifyActiveModel("abc", expectedVersion); 181 } 182 verifyActiveRussianModel()183 private void verifyActiveRussianModel() { 184 verifyActiveModel("привет", V804_RU_TAG); 185 } 186 } 187