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"
35 class MockAudioHistoryHandler
: public HotwordAudioHistoryHandler
{
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_
;
62 int get_audio_history_calls_
;
63 scoped_ptr
<history::WebHistoryService
> web_history_
;
66 class MockHotwordService
: public HotwordService
{
68 explicit MockHotwordService(Profile
* profile
)
69 : HotwordService(profile
),
73 bool UninstallHotwordExtension(ExtensionService
* extension_service
) override
{
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)
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
)
90 .SetLocation(extensions::Manifest::EXTERNAL_COMPONENT
)
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_
; }
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
)));
120 class HotwordServiceTest
:
121 public extensions::ExtensionServiceTestBase
,
122 public ::testing::WithParamInterface
<const char*> {
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
);
132 g_browser_process
->SetApplicationLocale(new_locale
);
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();
143 extensions::ExtensionServiceTestBase::SetUp();
146 void TearDown() override
{
147 #if defined(OS_CHROMEOS)
148 DCHECK(chromeos::CrasAudioHandler::IsInitialized());
149 chromeos::CrasAudioHandler::Shutdown();
153 std::string extension_id_
;
156 INSTANTIATE_TEST_CASE_P(HotwordServiceTests
,
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;
169 bool hotwording_enabled
= false;
172 // Check that the service exists so that a NULL service be ruled out in
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();
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();
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();
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_
));
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()));
304 // Disabled due to http://crbug.com/503963.
305 // EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(profile()));
308 // Different but valid locale so expect uninstall.
309 EXPECT_TRUE(hotword_service
->MaybeReinstallHotwordExtension());
310 EXPECT_EQ(1, hotword_service
->uninstall_count());
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_
));
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());
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()));
335 // Disabled due to http://crbug.com/503963.
336 // EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(profile()));
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
)
348 base::CommandLine::ForCurrentProcess()->AppendSwitch(
349 switches::kEnableExperimentalHotwordHardware
);
351 InitializeEmptyExtensionService();
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
)
417 InitializeEmptyExtensionService();
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());
446 profile()->GetPrefs()->SetBoolean(prefs::kHotwordAlwaysOnSearchEnabled
,
448 EXPECT_FALSE(hotword_service
->IsAlwaysOnEnabled());
451 TEST_P(HotwordServiceTest
, IsSometimesOnEnabled
) {
452 InitializeEmptyExtensionService();
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_
);
465 EXPECT_FALSE(hotword_service
->IsSometimesOnEnabled());
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());
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
)
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());
491 profile()->GetPrefs()->SetBoolean(prefs::kHotwordSearchEnabled
, true);
492 EXPECT_FALSE(hotword_service
->IsSometimesOnEnabled());
494 // Disable always-on.
495 profile()->GetPrefs()->SetBoolean(prefs::kHotwordAlwaysOnSearchEnabled
,
497 EXPECT_FALSE(hotword_service
->IsSometimesOnEnabled());
500 TEST_P(HotwordServiceTest
, AudioHistorySyncOccurs
) {
501 InitializeEmptyExtensionService();
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();