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.util.Log; 22 import android.view.textclassifier.TextClassification; 23 import android.view.textclassifier.TextClassification.Request; 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 smokeTest()73 public void smokeTest() throws Exception { 74 extServicesTextClassifierRule.addDeviceConfigOverride( 75 "manifest_url_annotator_en", V804_EN_ANNOTATOR_MANIFEST_URL); 76 77 assertWithRetries(() -> verifyActiveEnglishModel(V804_EN_TAG)); 78 } 79 80 @Test downgradeModel()81 public void downgradeModel() throws Exception { 82 // Download an experimental model. 83 extServicesTextClassifierRule.addDeviceConfigOverride( 84 "manifest_url_annotator_en", EXPERIMENTAL_EN_ANNOTATOR_MANIFEST_URL); 85 86 assertWithRetries(() -> verifyActiveEnglishModel(EXPERIMENTAL_EN_TAG)); 87 88 // Downgrade to an older model. 89 extServicesTextClassifierRule.addDeviceConfigOverride( 90 "manifest_url_annotator_en", V804_EN_ANNOTATOR_MANIFEST_URL); 91 92 assertWithRetries(() -> verifyActiveEnglishModel(V804_EN_TAG)); 93 } 94 95 @Test upgradeModel()96 public void upgradeModel() throws Exception { 97 // Download a model. 98 extServicesTextClassifierRule.addDeviceConfigOverride( 99 "manifest_url_annotator_en", V804_EN_ANNOTATOR_MANIFEST_URL); 100 101 assertWithRetries(() -> verifyActiveEnglishModel(V804_EN_TAG)); 102 103 // Upgrade to an experimental model. 104 extServicesTextClassifierRule.addDeviceConfigOverride( 105 "manifest_url_annotator_en", EXPERIMENTAL_EN_ANNOTATOR_MANIFEST_URL); 106 107 assertWithRetries(() -> verifyActiveEnglishModel(EXPERIMENTAL_EN_TAG)); 108 } 109 110 @Test clearFlag()111 public void clearFlag() throws Exception { 112 // Download a new model. 113 extServicesTextClassifierRule.addDeviceConfigOverride( 114 "manifest_url_annotator_en", EXPERIMENTAL_EN_ANNOTATOR_MANIFEST_URL); 115 116 assertWithRetries(() -> verifyActiveEnglishModel(EXPERIMENTAL_EN_TAG)); 117 118 // Revert the flag. 119 extServicesTextClassifierRule.addDeviceConfigOverride("manifest_url_annotator_en", ""); 120 // Fallback to use the universal model. 121 assertWithRetries( 122 () -> verifyActiveModel(/* text= */ "abc", /* expectedVersion= */ FACTORY_MODEL_TAG)); 123 } 124 125 @Test modelsForMultipleLanguagesDownloaded()126 public void modelsForMultipleLanguagesDownloaded() throws Exception { 127 extServicesTextClassifierRule.addDeviceConfigOverride("multi_language_support_enabled", "true"); 128 extServicesTextClassifierRule.addDeviceConfigOverride( 129 "testing_locale_list_override", "en-US,ru-RU"); 130 131 // download en model 132 extServicesTextClassifierRule.addDeviceConfigOverride( 133 "manifest_url_annotator_en", EXPERIMENTAL_EN_ANNOTATOR_MANIFEST_URL); 134 135 // download ru model 136 extServicesTextClassifierRule.addDeviceConfigOverride( 137 "manifest_url_annotator_ru", V804_RU_ANNOTATOR_MANIFEST_URL); 138 assertWithRetries(() -> verifyActiveEnglishModel(EXPERIMENTAL_EN_TAG)); 139 140 assertWithRetries(this::verifyActiveRussianModel); 141 142 assertWithRetries( 143 () -> verifyActiveModel(/* text= */ "français", /* expectedVersion= */ FACTORY_MODEL_TAG)); 144 } 145 assertWithRetries(Runnable assertRunnable)146 private void assertWithRetries(Runnable assertRunnable) throws Exception { 147 for (int i = 0; i < ASSERT_MAX_ATTEMPTS; i++) { 148 try { 149 extServicesTextClassifierRule.overrideDeviceConfig(); 150 assertRunnable.run(); 151 break; // success. Bail out. 152 } catch (AssertionError ex) { 153 if (i == ASSERT_MAX_ATTEMPTS - 1) { // last attempt, give up. 154 extServicesTextClassifierRule.dumpDefaultTextClassifierService(); 155 throw ex; 156 } else { 157 Thread.sleep(ASSERT_SLEEP_BEFORE_RETRY_MS); 158 } 159 } catch (Exception unknownException) { 160 throw unknownException; 161 } 162 } 163 } 164 verifyActiveModel(String text, String expectedVersion)165 private void verifyActiveModel(String text, String expectedVersion) { 166 TextClassification textClassification = 167 extServicesTextClassifierRule 168 .getTextClassifier() 169 .classifyText(new Request.Builder(text, 0, text.length()).build()); 170 // The result id contains the name of the just used model. 171 Log.d(TAG, "verifyActiveModel. TextClassification ID: " + textClassification.getId()); 172 assertThat(textClassification.getId()).contains(expectedVersion); 173 } 174 verifyActiveEnglishModel(String expectedVersion)175 private void verifyActiveEnglishModel(String expectedVersion) { 176 verifyActiveModel("abc", expectedVersion); 177 } 178 verifyActiveRussianModel()179 private void verifyActiveRussianModel() { 180 verifyActiveModel("привет", V804_RU_TAG); 181 } 182 } 183