1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/command_line.h"
6 #include "base/memory/scoped_ptr.h"
7 #include "base/metrics/field_trial.h"
8 #include "base/prefs/pref_service.h"
9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/extensions/extension_service_test_base.h"
11 #include "chrome/browser/extensions/test_extension_service.h"
12 #include "chrome/browser/search/hotword_service.h"
13 #include "chrome/browser/search/hotword_service_factory.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/common/extensions/extension_constants.h"
16 #include "chrome/common/pref_names.h"
17 #include "chrome/test/base/testing_profile.h"
18 #include "content/public/test/test_browser_thread_bundle.h"
19 #include "extensions/browser/extension_system.h"
20 #include "extensions/common/extension.h"
21 #include "extensions/common/extension_builder.h"
22 #include "extensions/common/manifest.h"
23 #include "extensions/common/one_shot_event.h"
24 #include "testing/gtest/include/gtest/gtest.h"
28 class MockHotwordService : public HotwordService {
30 explicit MockHotwordService(Profile* profile)
31 : HotwordService(profile),
35 bool UninstallHotwordExtension(ExtensionService* extension_service) override {
37 return HotwordService::UninstallHotwordExtension(extension_service);
40 void InstallHotwordExtensionFromWebstore() override {
41 scoped_ptr<base::DictionaryValue> manifest =
42 extensions::DictionaryBuilder()
43 .Set("name", "Hotword Test Extension")
44 .Set("version", "1.0")
45 .Set("manifest_version", 2)
47 scoped_refptr<extensions::Extension> extension =
48 extensions::ExtensionBuilder().SetManifest(manifest.Pass())
49 .AddFlags(extensions::Extension::FROM_WEBSTORE
50 | extensions::Extension::WAS_INSTALLED_BY_DEFAULT)
52 .SetLocation(extensions::Manifest::EXTERNAL_COMPONENT)
54 ASSERT_TRUE(extension.get());
55 service_->OnExtensionInstalled(extension.get(), syncer::StringOrdinal());
59 int uninstall_count() { return uninstall_count_; }
61 void SetExtensionService(ExtensionService* service) { service_ = service; }
62 void SetExtensionId(const std::string& extension_id) {
63 extension_id_ = extension_id;
66 ExtensionService* extension_service() { return service_; }
69 ExtensionService* service_;
71 std::string extension_id_;
74 KeyedService* BuildMockHotwordService(content::BrowserContext* context) {
75 return new MockHotwordService(static_cast<Profile*>(context));
80 class HotwordServiceTest :
81 public extensions::ExtensionServiceTestBase,
82 public ::testing::WithParamInterface<const char*> {
84 HotwordServiceTest() : field_trial_list_(NULL) {}
85 virtual ~HotwordServiceTest() {}
87 void SetApplicationLocale(Profile* profile, const std::string& new_locale) {
88 #if defined(OS_CHROMEOS)
89 // On ChromeOS locale is per-profile.
90 profile->GetPrefs()->SetString(prefs::kApplicationLocale, new_locale);
92 g_browser_process->SetApplicationLocale(new_locale);
96 void SetUp() override {
97 extension_id_ = GetParam();
98 if (extension_id_ == extension_misc::kHotwordSharedModuleId) {
99 base::CommandLine::ForCurrentProcess()->AppendSwitch(
100 switches::kEnableExperimentalHotwording);
103 extensions::ExtensionServiceTestBase::SetUp();
106 base::FieldTrialList field_trial_list_;
107 std::string extension_id_;
110 INSTANTIATE_TEST_CASE_P(HotwordServiceTests,
113 extension_misc::kHotwordExtensionId,
114 extension_misc::kHotwordSharedModuleId));
116 TEST_P(HotwordServiceTest, IsHotwordAllowedBadFieldTrial) {
117 TestingProfile::Builder profile_builder;
118 scoped_ptr<TestingProfile> profile = profile_builder.Build();
120 HotwordServiceFactory* hotword_service_factory =
121 HotwordServiceFactory::GetInstance();
123 // Check that the service exists so that a NULL service be ruled out in
125 HotwordService* hotword_service =
126 hotword_service_factory->GetForProfile(profile.get());
127 EXPECT_TRUE(hotword_service != NULL);
129 // When the field trial is empty or Disabled, it should not be allowed.
130 std::string group = base::FieldTrialList::FindFullName(
131 hotword_internal::kHotwordFieldTrialName);
132 EXPECT_TRUE(group.empty());
133 EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(profile.get()));
135 ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
136 hotword_internal::kHotwordFieldTrialName,
137 hotword_internal::kHotwordFieldTrialDisabledGroupName));
138 group = base::FieldTrialList::FindFullName(
139 hotword_internal::kHotwordFieldTrialName);
140 EXPECT_TRUE(group ==hotword_internal::kHotwordFieldTrialDisabledGroupName);
141 EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(profile.get()));
143 // Set a valid locale with invalid field trial to be sure it is
145 SetApplicationLocale(static_cast<Profile*>(profile.get()), "en");
146 EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(profile.get()));
148 // Test that incognito returns false as well.
149 EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(
150 profile->GetOffTheRecordProfile()));
153 TEST_P(HotwordServiceTest, IsHotwordAllowedLocale) {
154 TestingProfile::Builder profile_builder;
155 scoped_ptr<TestingProfile> profile = profile_builder.Build();
157 HotwordServiceFactory* hotword_service_factory =
158 HotwordServiceFactory::GetInstance();
160 // Check that the service exists so that a NULL service be ruled out in
162 HotwordService* hotword_service =
163 hotword_service_factory->GetForProfile(profile.get());
164 EXPECT_TRUE(hotword_service != NULL);
166 // Set the field trial to a valid one.
167 ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
168 hotword_internal::kHotwordFieldTrialName, "Good"));
170 // Set the language to an invalid one.
171 SetApplicationLocale(static_cast<Profile*>(profile.get()), "non-valid");
172 EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(profile.get()));
174 // Now with valid locales it should be fine.
175 SetApplicationLocale(static_cast<Profile*>(profile.get()), "en");
176 EXPECT_TRUE(HotwordServiceFactory::IsHotwordAllowed(profile.get()));
177 SetApplicationLocale(static_cast<Profile*>(profile.get()), "en-US");
178 EXPECT_TRUE(HotwordServiceFactory::IsHotwordAllowed(profile.get()));
179 SetApplicationLocale(static_cast<Profile*>(profile.get()), "en_us");
180 EXPECT_TRUE(HotwordServiceFactory::IsHotwordAllowed(profile.get()));
181 SetApplicationLocale(static_cast<Profile*>(profile.get()), "de_DE");
182 EXPECT_TRUE(HotwordServiceFactory::IsHotwordAllowed(profile.get()));
183 SetApplicationLocale(static_cast<Profile*>(profile.get()), "fr_fr");
184 EXPECT_TRUE(HotwordServiceFactory::IsHotwordAllowed(profile.get()));
186 // Test that incognito even with a valid locale and valid field trial
187 // still returns false.
188 Profile* otr_profile = profile->GetOffTheRecordProfile();
189 SetApplicationLocale(otr_profile, "en");
190 EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(otr_profile));
193 TEST_P(HotwordServiceTest, AudioLoggingPrefSetCorrectly) {
194 TestingProfile::Builder profile_builder;
195 scoped_ptr<TestingProfile> profile = profile_builder.Build();
197 HotwordServiceFactory* hotword_service_factory =
198 HotwordServiceFactory::GetInstance();
199 HotwordService* hotword_service =
200 hotword_service_factory->GetForProfile(profile.get());
201 EXPECT_TRUE(hotword_service != NULL);
203 // If it's a fresh profile, although the default value is true,
204 // it should return false if the preference has never been set.
205 EXPECT_FALSE(hotword_service->IsOptedIntoAudioLogging());
208 TEST_P(HotwordServiceTest, ShouldReinstallExtension) {
209 // Set the field trial to a valid one.
210 ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
211 hotword_internal::kHotwordFieldTrialName, "Install"));
213 InitializeEmptyExtensionService();
215 HotwordServiceFactory* hotword_service_factory =
216 HotwordServiceFactory::GetInstance();
218 MockHotwordService* hotword_service = static_cast<MockHotwordService*>(
219 hotword_service_factory->SetTestingFactoryAndUse(
220 profile(), BuildMockHotwordService));
221 EXPECT_TRUE(hotword_service != NULL);
222 hotword_service->SetExtensionId(extension_id_);
224 // If no locale has been set, no reason to uninstall.
225 EXPECT_FALSE(hotword_service->ShouldReinstallHotwordExtension());
227 SetApplicationLocale(profile(), "en");
228 hotword_service->SetPreviousLanguagePref();
230 // Now a locale is set, but it hasn't changed.
231 EXPECT_FALSE(hotword_service->ShouldReinstallHotwordExtension());
233 SetApplicationLocale(profile(), "fr_fr");
235 // Now it's a different locale so it should uninstall.
236 EXPECT_TRUE(hotword_service->ShouldReinstallHotwordExtension());
239 TEST_P(HotwordServiceTest, PreviousLanguageSetOnInstall) {
240 // Set the field trial to a valid one.
241 ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
242 hotword_internal::kHotwordFieldTrialName, "Install"));
244 InitializeEmptyExtensionService();
247 HotwordServiceFactory* hotword_service_factory =
248 HotwordServiceFactory::GetInstance();
250 MockHotwordService* hotword_service = static_cast<MockHotwordService*>(
251 hotword_service_factory->SetTestingFactoryAndUse(
252 profile(), BuildMockHotwordService));
253 EXPECT_TRUE(hotword_service != NULL);
254 hotword_service->SetExtensionService(service());
255 hotword_service->SetExtensionId(extension_id_);
257 // If no locale has been set, no reason to uninstall.
258 EXPECT_FALSE(hotword_service->ShouldReinstallHotwordExtension());
260 SetApplicationLocale(profile(), "test_locale");
262 hotword_service->InstallHotwordExtensionFromWebstore();
263 base::MessageLoop::current()->RunUntilIdle();
265 EXPECT_EQ("test_locale",
266 profile()->GetPrefs()->GetString(prefs::kHotwordPreviousLanguage));
269 TEST_P(HotwordServiceTest, UninstallReinstallTriggeredCorrectly) {
270 // Set the field trial to a valid one.
271 ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
272 hotword_internal::kHotwordFieldTrialName, "Install"));
274 InitializeEmptyExtensionService();
277 HotwordServiceFactory* hotword_service_factory =
278 HotwordServiceFactory::GetInstance();
280 MockHotwordService* hotword_service = static_cast<MockHotwordService*>(
281 hotword_service_factory->SetTestingFactoryAndUse(
282 profile(), BuildMockHotwordService));
283 EXPECT_TRUE(hotword_service != NULL);
284 hotword_service->SetExtensionService(service());
285 hotword_service->SetExtensionId(extension_id_);
287 // Initialize the locale to "en".
288 SetApplicationLocale(profile(), "en");
290 // The previous locale should not be set. No reason to uninstall.
291 EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension());
293 // Do an initial installation.
294 hotword_service->InstallHotwordExtensionFromWebstore();
295 base::MessageLoop::current()->RunUntilIdle();
297 profile()->GetPrefs()->GetString(prefs::kHotwordPreviousLanguage));
299 if (extension_id_ == extension_misc::kHotwordSharedModuleId) {
300 // Shared module is installed and enabled.
301 EXPECT_EQ(0U, registry()->disabled_extensions().size());
302 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id_));
304 // Verify the extension is installed but disabled.
305 EXPECT_EQ(1U, registry()->disabled_extensions().size());
306 EXPECT_TRUE(registry()->disabled_extensions().Contains(extension_id_));
309 // The previous locale should be set but should match the current
310 // locale. No reason to uninstall.
311 EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension());
313 // Switch the locale to a valid but different one.
314 SetApplicationLocale(profile(), "fr_fr");
315 EXPECT_TRUE(HotwordServiceFactory::IsHotwordAllowed(profile()));
317 // Different but valid locale so expect uninstall.
318 EXPECT_TRUE(hotword_service->MaybeReinstallHotwordExtension());
319 EXPECT_EQ(1, hotword_service->uninstall_count());
321 profile()->GetPrefs()->GetString(prefs::kHotwordPreviousLanguage));
323 if (extension_id_ == extension_misc::kHotwordSharedModuleId) {
324 // Shared module is installed and enabled.
325 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id_));
327 // Verify the extension is installed. It's still disabled.
328 EXPECT_TRUE(registry()->disabled_extensions().Contains(extension_id_));
331 // Switch the locale to an invalid one.
332 SetApplicationLocale(profile(), "invalid");
333 EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(profile()));
334 EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension());
336 profile()->GetPrefs()->GetString(prefs::kHotwordPreviousLanguage));
338 // If the locale is set back to the last valid one, then an uninstall-install
339 // shouldn't be needed.
340 SetApplicationLocale(profile(), "fr_fr");
341 EXPECT_TRUE(HotwordServiceFactory::IsHotwordAllowed(profile()));
342 EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension());
343 EXPECT_EQ(1, hotword_service->uninstall_count()); // no change
346 TEST_P(HotwordServiceTest, DisableAlwaysOnOnLanguageChange) {
347 // Bypass test for old hotwording.
348 if (extension_id_ != extension_misc::kHotwordSharedModuleId)
351 // Set the field trial to a valid one.
352 ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
353 hotword_internal::kHotwordFieldTrialName, "Install"));
355 InitializeEmptyExtensionService();
359 profile()->GetPrefs()->SetBoolean(prefs::kHotwordAlwaysOnSearchEnabled, true);
361 HotwordServiceFactory* hotword_service_factory =
362 HotwordServiceFactory::GetInstance();
364 MockHotwordService* hotword_service = static_cast<MockHotwordService*>(
365 hotword_service_factory->SetTestingFactoryAndUse(
366 profile(), BuildMockHotwordService));
367 EXPECT_TRUE(hotword_service != NULL);
368 hotword_service->SetExtensionService(service());
369 hotword_service->SetExtensionId(extension_id_);
371 // Initialize the locale to "en".
372 SetApplicationLocale(profile(), "en");
374 // The previous locale should not be set. No reason to uninstall.
375 EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension());
376 EXPECT_TRUE(hotword_service->IsAlwaysOnEnabled());
378 // Do an initial installation.
379 hotword_service->InstallHotwordExtensionFromWebstore();
380 base::MessageLoop::current()->RunUntilIdle();
382 // The previous locale should be set but should match the current
383 // locale. No reason to uninstall.
384 EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension());
385 EXPECT_TRUE(hotword_service->IsAlwaysOnEnabled());
387 // Switch the locale to a valid but different one.
388 SetApplicationLocale(profile(), "fr_fr");
389 EXPECT_TRUE(HotwordServiceFactory::IsHotwordAllowed(profile()));
391 // Different but valid locale so expect uninstall.
392 EXPECT_TRUE(hotword_service->MaybeReinstallHotwordExtension());
393 EXPECT_FALSE(hotword_service->IsAlwaysOnEnabled());
395 // Re-enable always-on.
396 profile()->GetPrefs()->SetBoolean(prefs::kHotwordAlwaysOnSearchEnabled, true);
398 // Switch the locale to an invalid one.
399 SetApplicationLocale(profile(), "invalid");
400 EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(profile()));
401 EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension());
402 EXPECT_TRUE(hotword_service->IsAlwaysOnEnabled());
404 // If the locale is set back to the last valid one, then an uninstall-install
405 // shouldn't be needed.
406 SetApplicationLocale(profile(), "fr_fr");
407 EXPECT_TRUE(HotwordServiceFactory::IsHotwordAllowed(profile()));
408 EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension());
409 EXPECT_TRUE(hotword_service->IsAlwaysOnEnabled());