ExtensionSyncService: listen for relevant changes instead of being explicitly called...
[chromium-blink-merge.git] / chrome / browser / search / hotword_service_unittest.cc
blobc1571fbd7cc02e31d4be6fbd0639b93965a10ee7
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 "base/test/test_simple_task_runner.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/extensions/extension_service_test_base.h"
12 #include "chrome/browser/extensions/test_extension_service.h"
13 #include "chrome/browser/search/hotword_audio_history_handler.h"
14 #include "chrome/browser/search/hotword_service.h"
15 #include "chrome/browser/search/hotword_service_factory.h"
16 #include "chrome/common/chrome_switches.h"
17 #include "chrome/common/extensions/extension_constants.h"
18 #include "chrome/common/pref_names.h"
19 #include "chrome/test/base/testing_profile.h"
20 #include "components/history/core/browser/web_history_service.h"
21 #include "content/public/test/test_browser_thread_bundle.h"
22 #include "extensions/browser/extension_system.h"
23 #include "extensions/common/extension.h"
24 #include "extensions/common/extension_builder.h"
25 #include "extensions/common/manifest.h"
26 #include "extensions/common/one_shot_event.h"
27 #include "testing/gtest/include/gtest/gtest.h"
29 #if defined(OS_CHROMEOS)
30 #include "chromeos/audio/cras_audio_handler.h"
31 #endif
33 namespace {
35 class MockAudioHistoryHandler : public HotwordAudioHistoryHandler {
36 public:
37 MockAudioHistoryHandler(
38 content::BrowserContext* context,
39 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
40 history::WebHistoryService* web_history)
41 : HotwordAudioHistoryHandler(context, task_runner),
42 get_audio_history_calls_(0),
43 web_history_(web_history) {
45 ~MockAudioHistoryHandler() override {}
47 void GetAudioHistoryEnabled(
48 const HotwordAudioHistoryCallback& callback) override {
49 get_audio_history_calls_++;
50 callback.Run(true, true);
53 history::WebHistoryService* GetWebHistory() override {
54 return web_history_.get();
57 int GetAudioHistoryCalls() {
58 return get_audio_history_calls_;
61 private:
62 int get_audio_history_calls_;
63 scoped_ptr<history::WebHistoryService> web_history_;
66 class MockHotwordService : public HotwordService {
67 public:
68 explicit MockHotwordService(Profile* profile)
69 : HotwordService(profile),
70 uninstall_count_(0) {
73 bool UninstallHotwordExtension(ExtensionService* extension_service) override {
74 uninstall_count_++;
75 return HotwordService::UninstallHotwordExtension(extension_service);
78 void InstallHotwordExtensionFromWebstore(int num_tries) override {
79 scoped_ptr<base::DictionaryValue> manifest =
80 extensions::DictionaryBuilder()
81 .Set("name", "Hotword Test Extension")
82 .Set("version", "1.0")
83 .Set("manifest_version", 2)
84 .Build();
85 scoped_refptr<extensions::Extension> extension =
86 extensions::ExtensionBuilder().SetManifest(manifest.Pass())
87 .AddFlags(extensions::Extension::FROM_WEBSTORE
88 | extensions::Extension::WAS_INSTALLED_BY_DEFAULT)
89 .SetID(extension_id_)
90 .SetLocation(extensions::Manifest::EXTERNAL_COMPONENT)
91 .Build();
92 ASSERT_TRUE(extension.get());
93 service_->OnExtensionInstalled(extension.get(), syncer::StringOrdinal());
97 int uninstall_count() { return uninstall_count_; }
99 void SetExtensionService(ExtensionService* service) { service_ = service; }
100 void SetExtensionId(const std::string& extension_id) {
101 extension_id_ = extension_id;
104 ExtensionService* extension_service() { return service_; }
106 private:
107 ExtensionService* service_;
108 int uninstall_count_;
109 std::string extension_id_;
112 scoped_ptr<KeyedService> BuildMockHotwordService(
113 content::BrowserContext* context) {
114 return make_scoped_ptr(
115 new MockHotwordService(static_cast<Profile*>(context)));
118 } // namespace
120 class HotwordServiceTest :
121 public extensions::ExtensionServiceTestBase,
122 public ::testing::WithParamInterface<const char*> {
123 protected:
124 HotwordServiceTest() {}
125 virtual ~HotwordServiceTest() {}
127 void SetApplicationLocale(Profile* profile, const std::string& new_locale) {
128 #if defined(OS_CHROMEOS)
129 // On ChromeOS locale is per-profile.
130 profile->GetPrefs()->SetString(prefs::kApplicationLocale, new_locale);
131 #else
132 g_browser_process->SetApplicationLocale(new_locale);
133 #endif
136 void SetUp() override {
137 extension_id_ = GetParam();
138 #if defined(OS_CHROMEOS)
139 // Tests on chromeos need to have the handler initialized.
140 chromeos::CrasAudioHandler::InitializeForTesting();
141 #endif
143 extensions::ExtensionServiceTestBase::SetUp();
146 void TearDown() override {
147 #if defined(OS_CHROMEOS)
148 DCHECK(chromeos::CrasAudioHandler::IsInitialized());
149 chromeos::CrasAudioHandler::Shutdown();
150 #endif
153 std::string extension_id_;
156 INSTANTIATE_TEST_CASE_P(HotwordServiceTests,
157 HotwordServiceTest,
158 ::testing::Values(
159 extension_misc::kHotwordSharedModuleId));
161 // Disabled due to http://crbug.com/503963.
162 TEST_P(HotwordServiceTest, DISABLED_IsHotwordAllowedLocale) {
163 TestingProfile::Builder profile_builder;
164 scoped_ptr<TestingProfile> profile = profile_builder.Build();
166 #if defined(ENABLE_HOTWORDING)
167 bool hotwording_enabled = true;
168 #else
169 bool hotwording_enabled = false;
170 #endif
172 // Check that the service exists so that a NULL service be ruled out in
173 // following tests.
174 HotwordService* hotword_service =
175 HotwordServiceFactory::GetForProfile(profile.get());
176 EXPECT_TRUE(hotword_service != NULL);
178 // Set the language to an invalid one.
179 SetApplicationLocale(static_cast<Profile*>(profile.get()), "non-valid");
180 EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(profile.get()));
182 // Now with valid locales it should be fine.
183 SetApplicationLocale(static_cast<Profile*>(profile.get()), "en");
184 EXPECT_EQ(hotwording_enabled,
185 HotwordServiceFactory::IsHotwordAllowed(profile.get()));
186 SetApplicationLocale(static_cast<Profile*>(profile.get()), "en-US");
187 EXPECT_EQ(hotwording_enabled,
188 HotwordServiceFactory::IsHotwordAllowed(profile.get()));
189 SetApplicationLocale(static_cast<Profile*>(profile.get()), "en_us");
190 EXPECT_EQ(hotwording_enabled,
191 HotwordServiceFactory::IsHotwordAllowed(profile.get()));
192 SetApplicationLocale(static_cast<Profile*>(profile.get()), "de_DE");
193 EXPECT_EQ(hotwording_enabled,
194 HotwordServiceFactory::IsHotwordAllowed(profile.get()));
195 SetApplicationLocale(static_cast<Profile*>(profile.get()), "fr_fr");
196 EXPECT_EQ(hotwording_enabled,
197 HotwordServiceFactory::IsHotwordAllowed(profile.get()));
199 // Test that incognito even with a valid locale and valid field trial
200 // still returns false.
201 Profile* otr_profile = profile->GetOffTheRecordProfile();
202 SetApplicationLocale(otr_profile, "en");
203 EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(otr_profile));
206 TEST_P(HotwordServiceTest, ShouldReinstallExtension) {
207 InitializeEmptyExtensionService();
209 HotwordServiceFactory* hotword_service_factory =
210 HotwordServiceFactory::GetInstance();
212 MockHotwordService* hotword_service = static_cast<MockHotwordService*>(
213 hotword_service_factory->SetTestingFactoryAndUse(
214 profile(), BuildMockHotwordService));
215 ASSERT_TRUE(hotword_service != NULL);
216 hotword_service->SetExtensionId(extension_id_);
218 // If no locale has been set, no reason to uninstall.
219 EXPECT_FALSE(hotword_service->ShouldReinstallHotwordExtension());
221 SetApplicationLocale(profile(), "en");
222 hotword_service->SetPreviousLanguagePref();
224 // Now a locale is set, but it hasn't changed.
225 EXPECT_FALSE(hotword_service->ShouldReinstallHotwordExtension());
227 SetApplicationLocale(profile(), "fr_fr");
229 // Now it's a different locale so it should uninstall.
230 EXPECT_TRUE(hotword_service->ShouldReinstallHotwordExtension());
233 TEST_P(HotwordServiceTest, PreviousLanguageSetOnInstall) {
234 InitializeEmptyExtensionService();
235 service_->Init();
237 HotwordServiceFactory* hotword_service_factory =
238 HotwordServiceFactory::GetInstance();
240 MockHotwordService* hotword_service = static_cast<MockHotwordService*>(
241 hotword_service_factory->SetTestingFactoryAndUse(
242 profile(), BuildMockHotwordService));
243 ASSERT_TRUE(hotword_service != NULL);
244 hotword_service->SetExtensionService(service());
245 hotword_service->SetExtensionId(extension_id_);
247 // If no locale has been set, no reason to uninstall.
248 EXPECT_FALSE(hotword_service->ShouldReinstallHotwordExtension());
250 SetApplicationLocale(profile(), "test_locale");
252 hotword_service->InstallHotwordExtensionFromWebstore(1);
253 base::MessageLoop::current()->RunUntilIdle();
255 EXPECT_EQ("test_locale",
256 profile()->GetPrefs()->GetString(prefs::kHotwordPreviousLanguage));
259 TEST_P(HotwordServiceTest, UninstallReinstallTriggeredCorrectly) {
260 InitializeEmptyExtensionService();
261 service_->Init();
263 HotwordServiceFactory* hotword_service_factory =
264 HotwordServiceFactory::GetInstance();
266 MockHotwordService* hotword_service = static_cast<MockHotwordService*>(
267 hotword_service_factory->SetTestingFactoryAndUse(
268 profile(), BuildMockHotwordService));
269 ASSERT_TRUE(hotword_service != NULL);
270 hotword_service->SetExtensionService(service());
271 hotword_service->SetExtensionId(extension_id_);
273 // Initialize the locale to "en".
274 SetApplicationLocale(profile(), "en");
276 // The previous locale should not be set. No reason to uninstall.
277 EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension());
279 // Do an initial installation.
280 hotword_service->InstallHotwordExtensionFromWebstore(1);
281 base::MessageLoop::current()->RunUntilIdle();
282 EXPECT_EQ("en",
283 profile()->GetPrefs()->GetString(prefs::kHotwordPreviousLanguage));
285 if (extension_id_ == extension_misc::kHotwordSharedModuleId) {
286 // Shared module is installed and enabled.
287 EXPECT_EQ(0U, registry()->disabled_extensions().size());
288 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id_));
289 } else {
290 // Verify the extension is installed but disabled.
291 EXPECT_EQ(1U, registry()->disabled_extensions().size());
292 EXPECT_TRUE(registry()->disabled_extensions().Contains(extension_id_));
295 // The previous locale should be set but should match the current
296 // locale. No reason to uninstall.
297 EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension());
299 // Switch the locale to a valid but different one.
300 SetApplicationLocale(profile(), "fr_fr");
301 #if defined(ENABLE_HOTWORDING)
302 EXPECT_TRUE(HotwordServiceFactory::IsHotwordAllowed(profile()));
303 #else
304 // Disabled due to http://crbug.com/503963.
305 // EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(profile()));
306 #endif
308 // Different but valid locale so expect uninstall.
309 EXPECT_TRUE(hotword_service->MaybeReinstallHotwordExtension());
310 EXPECT_EQ(1, hotword_service->uninstall_count());
311 EXPECT_EQ("fr_fr",
312 profile()->GetPrefs()->GetString(prefs::kHotwordPreviousLanguage));
314 if (extension_id_ == extension_misc::kHotwordSharedModuleId) {
315 // Shared module is installed and enabled.
316 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id_));
317 } else {
318 // Verify the extension is installed. It's still disabled.
319 EXPECT_TRUE(registry()->disabled_extensions().Contains(extension_id_));
322 // Switch the locale to an invalid one.
323 SetApplicationLocale(profile(), "invalid");
324 EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(profile()));
325 EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension());
326 EXPECT_EQ("fr_fr",
327 profile()->GetPrefs()->GetString(prefs::kHotwordPreviousLanguage));
329 // If the locale is set back to the last valid one, then an uninstall-install
330 // shouldn't be needed.
331 SetApplicationLocale(profile(), "fr_fr");
332 #if defined(ENABLE_HOTWORDING)
333 EXPECT_TRUE(HotwordServiceFactory::IsHotwordAllowed(profile()));
334 #else
335 // Disabled due to http://crbug.com/503963.
336 // EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(profile()));
337 #endif
338 EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension());
339 EXPECT_EQ(1, hotword_service->uninstall_count()); // no change
342 TEST_P(HotwordServiceTest, DisableAlwaysOnOnLanguageChange) {
343 // Bypass test for old hotwording.
344 if (extension_id_ != extension_misc::kHotwordSharedModuleId)
345 return;
347 // Turn on Always On
348 base::CommandLine::ForCurrentProcess()->AppendSwitch(
349 switches::kEnableExperimentalHotwordHardware);
351 InitializeEmptyExtensionService();
352 service_->Init();
354 // Enable always-on.
355 profile()->GetPrefs()->SetBoolean(prefs::kHotwordAlwaysOnSearchEnabled, true);
357 HotwordServiceFactory* hotword_service_factory =
358 HotwordServiceFactory::GetInstance();
360 MockHotwordService* hotword_service = static_cast<MockHotwordService*>(
361 hotword_service_factory->SetTestingFactoryAndUse(
362 profile(), BuildMockHotwordService));
363 ASSERT_TRUE(hotword_service != NULL);
364 hotword_service->SetExtensionService(service());
365 hotword_service->SetExtensionId(extension_id_);
367 // Initialize the locale to "en_us".
368 SetApplicationLocale(profile(), "en_us");
370 // The previous locale should not be set. No reason to uninstall.
371 EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension());
372 EXPECT_TRUE(hotword_service->IsAlwaysOnEnabled());
374 // Do an initial installation.
375 hotword_service->InstallHotwordExtensionFromWebstore(1);
376 base::MessageLoop::current()->RunUntilIdle();
378 // The previous locale should be set but should match the current
379 // locale. No reason to uninstall.
380 EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension());
381 EXPECT_TRUE(hotword_service->IsAlwaysOnEnabled());
383 // TODO(kcarattini): Uncomment this sectione once we launch always-on
384 // in more languages.
385 // // Switch the locale to a valid but different one.
386 // SetApplicationLocale(profile(), "fr_fr");
387 // EXPECT_TRUE(HotwordServiceFactory::IsHotwordAllowed(profile()));
389 // // Different but valid locale so expect uninstall.
390 // EXPECT_TRUE(hotword_service->MaybeReinstallHotwordExtension());
391 // EXPECT_FALSE(hotword_service->IsAlwaysOnEnabled());
393 // Re-enable always-on.
394 profile()->GetPrefs()->SetBoolean(prefs::kHotwordAlwaysOnSearchEnabled, true);
396 // Switch the locale to an invalid one.
397 SetApplicationLocale(profile(), "invalid");
398 EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(profile()));
399 EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension());
400 EXPECT_TRUE(hotword_service->IsAlwaysOnEnabled());
402 // TODO(kcarattini): Uncomment this sectione once we launch always-on
403 // in more languages.
404 // // If the locale is set back to the last valid one, then an
405 // // uninstall-install 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());
412 TEST_P(HotwordServiceTest, IsAlwaysOnEnabled) {
413 // Bypass test for old hotwording.
414 if (extension_id_ != extension_misc::kHotwordSharedModuleId)
415 return;
417 InitializeEmptyExtensionService();
418 service_->Init();
419 HotwordServiceFactory* hotword_service_factory =
420 HotwordServiceFactory::GetInstance();
422 MockHotwordService* hotword_service = static_cast<MockHotwordService*>(
423 hotword_service_factory->SetTestingFactoryAndUse(
424 profile(), BuildMockHotwordService));
425 ASSERT_TRUE(hotword_service != NULL);
426 hotword_service->SetExtensionService(service());
427 hotword_service->SetExtensionId(extension_id_);
429 // No hardware available. Should never be true.
430 EXPECT_FALSE(hotword_service->IsAlwaysOnEnabled());
432 // Enable always-on, still not available.
433 profile()->GetPrefs()->SetBoolean(prefs::kHotwordAlwaysOnSearchEnabled, true);
434 EXPECT_FALSE(hotword_service->IsAlwaysOnEnabled());
436 // Enable regular hotwording, still not available.
437 profile()->GetPrefs()->SetBoolean(prefs::kHotwordSearchEnabled, true);
438 EXPECT_FALSE(hotword_service->IsAlwaysOnEnabled());
440 // Bypass hardware check.
441 base::CommandLine::ForCurrentProcess()->AppendSwitch(
442 switches::kEnableExperimentalHotwordHardware);
443 EXPECT_TRUE(hotword_service->IsAlwaysOnEnabled());
445 // Disable.
446 profile()->GetPrefs()->SetBoolean(prefs::kHotwordAlwaysOnSearchEnabled,
447 false);
448 EXPECT_FALSE(hotword_service->IsAlwaysOnEnabled());
451 TEST_P(HotwordServiceTest, IsSometimesOnEnabled) {
452 InitializeEmptyExtensionService();
453 service_->Init();
454 HotwordServiceFactory* hotword_service_factory =
455 HotwordServiceFactory::GetInstance();
457 MockHotwordService* hotword_service = static_cast<MockHotwordService*>(
458 hotword_service_factory->SetTestingFactoryAndUse(
459 profile(), BuildMockHotwordService));
460 ASSERT_TRUE(hotword_service != NULL);
461 hotword_service->SetExtensionService(service());
462 hotword_service->SetExtensionId(extension_id_);
464 // No pref set.
465 EXPECT_FALSE(hotword_service->IsSometimesOnEnabled());
467 // Set pref.
468 profile()->GetPrefs()->SetBoolean(prefs::kHotwordSearchEnabled, true);
469 EXPECT_TRUE(hotword_service->IsSometimesOnEnabled());
471 // Turn on always-on pref. Should have no effect.
472 profile()->GetPrefs()->SetBoolean(prefs::kHotwordAlwaysOnSearchEnabled, true);
473 EXPECT_TRUE(hotword_service->IsSometimesOnEnabled());
475 // Disable.
476 profile()->GetPrefs()->SetBoolean(prefs::kHotwordSearchEnabled, false);
477 EXPECT_FALSE(hotword_service->IsSometimesOnEnabled());
479 // Bypass rest of test for old hotwording.
480 if (extension_id_ != extension_misc::kHotwordSharedModuleId)
481 return;
483 // Bypass hardware check.
484 base::CommandLine::ForCurrentProcess()->AppendSwitch(
485 switches::kEnableExperimentalHotwordHardware);
487 // With hardware, only always-on is allowed.
488 EXPECT_FALSE(hotword_service->IsSometimesOnEnabled());
490 // Set pref.
491 profile()->GetPrefs()->SetBoolean(prefs::kHotwordSearchEnabled, true);
492 EXPECT_FALSE(hotword_service->IsSometimesOnEnabled());
494 // Disable always-on.
495 profile()->GetPrefs()->SetBoolean(prefs::kHotwordAlwaysOnSearchEnabled,
496 false);
497 EXPECT_FALSE(hotword_service->IsSometimesOnEnabled());
500 TEST_P(HotwordServiceTest, AudioHistorySyncOccurs) {
501 InitializeEmptyExtensionService();
502 service_->Init();
504 HotwordServiceFactory* hotword_service_factory =
505 HotwordServiceFactory::GetInstance();
507 MockHotwordService* hotword_service = static_cast<MockHotwordService*>(
508 hotword_service_factory->SetTestingFactoryAndUse(
509 profile(), BuildMockHotwordService));
510 ASSERT_TRUE(hotword_service != NULL);
511 hotword_service->SetExtensionService(service());
512 hotword_service->SetExtensionId(extension_id_);
514 scoped_refptr<base::TestSimpleTaskRunner> test_task_runner(
515 new base::TestSimpleTaskRunner());
516 MockAudioHistoryHandler* audio_history_handler =
517 new MockAudioHistoryHandler(profile(), test_task_runner, nullptr);
518 hotword_service->SetAudioHistoryHandler(audio_history_handler);
519 EXPECT_EQ(1, audio_history_handler->GetAudioHistoryCalls());
520 // We expect the next check for audio history to be in the queue.
521 EXPECT_EQ(base::TimeDelta::FromDays(1),
522 test_task_runner->NextPendingTaskDelay());
523 EXPECT_TRUE(test_task_runner->HasPendingTask());
524 test_task_runner->RunPendingTasks();
525 EXPECT_EQ(2, audio_history_handler->GetAudioHistoryCalls());
526 EXPECT_TRUE(test_task_runner->HasPendingTask());
527 test_task_runner->ClearPendingTasks();