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/prefs/pref_service.h"
8 #include "chrome/browser/extensions/api/hotword_private/hotword_private_api.h"
9 #include "chrome/browser/extensions/extension_apitest.h"
10 #include "chrome/browser/extensions/extension_service.h"
11 #include "chrome/browser/history/web_history_service_factory.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/search/hotword_audio_history_handler.h"
14 #include "chrome/browser/search/hotword_client.h"
15 #include "chrome/browser/search/hotword_service.h"
16 #include "chrome/browser/search/hotword_service_factory.h"
17 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
18 #include "chrome/browser/signin/signin_manager_factory.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "chrome/common/pref_names.h"
21 #include "components/history/core/browser/web_history_service.h"
22 #include "components/signin/core/browser/profile_oauth2_token_service.h"
23 #include "components/signin/core/browser/signin_manager.h"
24 #include "extensions/common/switches.h"
25 #include "extensions/test/extension_test_message_listener.h"
26 #include "net/url_request/url_request_context_getter.h"
30 const char kHotwordTestExtensionId
[] = "cpfhkdbjfdgdebcjlifoldbijinjfifp";
32 // Mock the web history service so that we don't make actual requests over the
34 class MockWebHistoryService
: public history::WebHistoryService
{
36 explicit MockWebHistoryService(Profile
* profile
)
38 ProfileOAuth2TokenServiceFactory::GetForProfile(profile
),
39 SigninManagerFactory::GetForProfile(profile
),
40 profile
->GetRequestContext()),
41 expected_success_(true),
42 expected_value_(false) {}
43 ~MockWebHistoryService() override
{}
45 // For both of the following functions, just call the callback to simulate
46 // a successful return from the url fetch.
47 void GetAudioHistoryEnabled(
48 const AudioWebHistoryCallback
& callback
) override
{
49 callback
.Run(expected_success_
, expected_value_
&& expected_success_
);
52 void SetAudioHistoryEnabled(
53 bool new_enabled_value
,
54 const AudioWebHistoryCallback
& callback
) override
{
55 callback
.Run(expected_success_
, new_enabled_value
&& expected_success_
);
58 void SetExpectedValue(bool expected_value
) {
59 expected_value_
= expected_value
;
62 void SetFailureState() {
63 expected_success_
= false;
67 bool expected_success_
;
71 // Make a mock audio history handler so that the method for getting the web
72 // history can be overridden.
73 class MockAudioHistoryHandler
: public HotwordAudioHistoryHandler
{
75 MockAudioHistoryHandler(content::BrowserContext
* context
,
76 history::WebHistoryService
* web_history
)
77 : HotwordAudioHistoryHandler(context
,
78 base::MessageLoop::current()->task_runner()),
79 web_history_(web_history
) {}
80 ~MockAudioHistoryHandler() override
{}
82 history::WebHistoryService
* GetWebHistory() override
{
83 return web_history_
.get();
87 scoped_ptr
<history::WebHistoryService
> web_history_
;
90 class MockHotwordService
: public HotwordService
{
92 explicit MockHotwordService(Profile
* profile
)
93 : HotwordService(profile
), service_available_(true) {}
94 ~MockHotwordService() override
{}
96 bool IsServiceAvailable() override
{ return service_available_
; }
98 void setServiceAvailable(bool available
) {
99 service_available_
= available
;
102 static scoped_ptr
<KeyedService
> Build(content::BrowserContext
* profile
) {
103 return make_scoped_ptr(
104 new MockHotwordService(static_cast<Profile
*>(profile
)));
107 LaunchMode
GetHotwordAudioVerificationLaunchMode() override
{
111 void SetHotwordAudioVerificationLaunchMode(const LaunchMode
& launch_mode
) {
112 launch_mode_
= launch_mode
;
116 bool service_available_
;
117 LaunchMode launch_mode_
;
119 DISALLOW_COPY_AND_ASSIGN(MockHotwordService
);
122 class MockHotwordClient
: public HotwordClient
{
125 : last_enabled_(false),
126 state_changed_count_(0),
127 recognized_count_(0) {
130 ~MockHotwordClient() override
{}
132 void OnHotwordStateChanged(bool enabled
) override
{
133 last_enabled_
= enabled
;
134 state_changed_count_
++;
137 void OnHotwordRecognized(
138 const scoped_refptr
<content::SpeechRecognitionSessionPreamble
>& preamble
)
139 override
{ recognized_count_
++; }
141 bool last_enabled() const { return last_enabled_
; }
142 int state_changed_count() const { return state_changed_count_
; }
143 int recognized_count() const { return recognized_count_
; }
147 int state_changed_count_
;
148 int recognized_count_
;
150 DISALLOW_COPY_AND_ASSIGN(MockHotwordClient
);
153 class HotwordPrivateApiTest
: public ExtensionApiTest
{
155 HotwordPrivateApiTest() {}
156 ~HotwordPrivateApiTest() override
{}
158 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
159 ExtensionApiTest::SetUpCommandLine(command_line
);
161 // Whitelist the test extensions (which all share a common ID) to use
163 command_line
->AppendSwitchASCII(
164 extensions::switches::kWhitelistedExtensionID
, kHotwordTestExtensionId
);
167 void SetUpOnMainThread() override
{
168 ExtensionApiTest::SetUpOnMainThread();
170 test_data_dir_
= test_data_dir_
.AppendASCII("hotword_private");
172 service_
= static_cast<MockHotwordService
*>(
173 HotwordServiceFactory::GetInstance()->SetTestingFactoryAndUse(
174 profile(), MockHotwordService::Build
));
177 MockHotwordService
* service() {
182 MockHotwordService
* service_
;
184 DISALLOW_COPY_AND_ASSIGN(HotwordPrivateApiTest
);
187 } // anonymous namespace
189 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, SetEnabled
) {
190 EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled
));
192 ExtensionTestMessageListener
listenerTrue("ready", false);
193 ASSERT_TRUE(RunComponentExtensionTest("setEnabledTrue")) << message_
;
194 EXPECT_TRUE(listenerTrue
.WaitUntilSatisfied());
195 EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled
));
197 ExtensionTestMessageListener
listenerFalse("ready", false);
198 ASSERT_TRUE(RunComponentExtensionTest("setEnabledFalse")) << message_
;
199 EXPECT_TRUE(listenerFalse
.WaitUntilSatisfied());
200 EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled
));
203 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, SetAudioLoggingEnabled
) {
204 EXPECT_FALSE(service()->IsOptedIntoAudioLogging());
205 EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
206 prefs::kHotwordAudioLoggingEnabled
));
208 ExtensionTestMessageListener
listenerTrue("ready", false);
209 ASSERT_TRUE(RunComponentExtensionTest("setAudioLoggingEnableTrue"))
211 EXPECT_TRUE(listenerTrue
.WaitUntilSatisfied());
212 EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(
213 prefs::kHotwordAudioLoggingEnabled
));
214 EXPECT_TRUE(service()->IsOptedIntoAudioLogging());
216 ExtensionTestMessageListener
listenerFalse("ready", false);
217 ASSERT_TRUE(RunComponentExtensionTest("setAudioLoggingEnableFalse"))
219 EXPECT_TRUE(listenerFalse
.WaitUntilSatisfied());
220 EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
221 prefs::kHotwordAudioLoggingEnabled
));
222 EXPECT_FALSE(service()->IsOptedIntoAudioLogging());
225 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, SetHotwordAlwaysOnSearchEnabled
) {
226 EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
227 prefs::kHotwordAlwaysOnSearchEnabled
));
229 ExtensionTestMessageListener
listener("ready", false);
230 ASSERT_TRUE(RunComponentExtensionTest("setHotwordAlwaysOnSearchEnableTrue"))
232 EXPECT_TRUE(listener
.WaitUntilSatisfied());
233 EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(
234 prefs::kHotwordAlwaysOnSearchEnabled
));
237 ASSERT_TRUE(RunComponentExtensionTest("setHotwordAlwaysOnSearchEnableFalse"))
239 EXPECT_TRUE(listener
.WaitUntilSatisfied());
240 EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
241 prefs::kHotwordAlwaysOnSearchEnabled
));
244 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, GetStatus
) {
245 ASSERT_TRUE(RunComponentExtensionTest("getEnabled")) << message_
;
248 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, IsAvailableTrue
) {
249 service()->setServiceAvailable(true);
250 ExtensionTestMessageListener
listener("available: true", false);
251 ASSERT_TRUE(RunComponentExtensionTest("isAvailable")) << message_
;
252 EXPECT_TRUE(listener
.WaitUntilSatisfied());
255 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, IsAvailableTrue_NoGet
) {
256 service()->setServiceAvailable(true);
257 ExtensionTestMessageListener
listener("available: false", false);
258 ASSERT_TRUE(RunComponentExtensionTest("isAvailableNoGet")) << message_
;
259 EXPECT_TRUE(listener
.WaitUntilSatisfied());
262 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, IsAvailableFalse
) {
263 service()->setServiceAvailable(false);
264 ExtensionTestMessageListener
listener("available: false", false);
265 ASSERT_TRUE(RunComponentExtensionTest("isAvailable")) << message_
;
266 EXPECT_TRUE(listener
.WaitUntilSatisfied());
269 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, AlwaysOnEnabled
) {
270 // Bypass the hotword hardware check.
271 base::CommandLine::ForCurrentProcess()->AppendSwitch(
272 switches::kEnableExperimentalHotwordHardware
);
275 ExtensionTestMessageListener
listener("alwaysOnEnabled: false",
277 ASSERT_TRUE(RunComponentExtensionTest("alwaysOnEnabled"))
279 EXPECT_TRUE(listener
.WaitUntilSatisfied());
282 profile()->GetPrefs()->SetBoolean(prefs::kHotwordAlwaysOnSearchEnabled
, true);
284 ExtensionTestMessageListener
listener("alwaysOnEnabled: true",
286 ASSERT_TRUE(RunComponentExtensionTest("alwaysOnEnabled"))
288 EXPECT_TRUE(listener
.WaitUntilSatisfied());
292 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, OnEnabledChanged
) {
293 // Trigger the pref registrar.
294 extensions::HotwordPrivateEventService::GetFactoryInstance();
295 ExtensionTestMessageListener
listener("ready", false);
297 LoadExtensionAsComponent(test_data_dir_
.AppendASCII("onEnabledChanged")));
298 EXPECT_TRUE(listener
.WaitUntilSatisfied());
300 ExtensionTestMessageListener
listenerNotification("notification", false);
301 profile()->GetPrefs()->SetBoolean(prefs::kHotwordSearchEnabled
, true);
302 EXPECT_TRUE(listenerNotification
.WaitUntilSatisfied());
304 listenerNotification
.Reset();
305 profile()->GetPrefs()->SetBoolean(prefs::kHotwordAlwaysOnSearchEnabled
,
307 EXPECT_TRUE(listenerNotification
.WaitUntilSatisfied());
309 listenerNotification
.Reset();
310 service()->StartTraining();
311 EXPECT_TRUE(listenerNotification
.WaitUntilSatisfied());
314 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, HotwordSession
) {
315 extensions::HotwordPrivateEventService::GetFactoryInstance();
316 ExtensionTestMessageListener
listener("ready", false);
317 LoadExtensionAsComponent(
318 test_data_dir_
.AppendASCII("hotwordSession"));
319 EXPECT_TRUE(listener
.WaitUntilSatisfied());
321 ExtensionTestMessageListener
listenerStopReady("stopReady", false);
322 ExtensionTestMessageListener
listenerStopped("stopped", false);
323 MockHotwordClient client
;
324 service()->RequestHotwordSession(&client
);
325 EXPECT_TRUE(listenerStopReady
.WaitUntilSatisfied());
326 service()->StopHotwordSession(&client
);
327 EXPECT_TRUE(listenerStopped
.WaitUntilSatisfied());
329 EXPECT_TRUE(client
.last_enabled());
330 EXPECT_EQ(1, client
.state_changed_count());
331 EXPECT_EQ(1, client
.recognized_count());
334 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, GetLaunchStateHotwordOnly
) {
335 service()->SetHotwordAudioVerificationLaunchMode(
336 HotwordService::HOTWORD_ONLY
);
337 ExtensionTestMessageListener
listener("launchMode: 0", false);
338 ASSERT_TRUE(RunComponentExtensionTest("getLaunchState")) << message_
;
339 EXPECT_TRUE(listener
.WaitUntilSatisfied());
342 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
,
343 GetLaunchStateHotwordAudioHistory
) {
344 service()->SetHotwordAudioVerificationLaunchMode(
345 HotwordService::HOTWORD_AND_AUDIO_HISTORY
);
346 ExtensionTestMessageListener
listener("launchMode: 1", false);
347 ASSERT_TRUE(RunComponentExtensionTest("getLaunchState")) << message_
;
348 EXPECT_TRUE(listener
.WaitUntilSatisfied());
351 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, OnFinalizeSpeakerModel
) {
352 // Trigger the pref registrar.
353 extensions::HotwordPrivateEventService::GetFactoryInstance();
354 ExtensionTestMessageListener
listener("ready", false);
356 LoadExtensionAsComponent(test_data_dir_
.AppendASCII(
357 "onFinalizeSpeakerModel")));
358 EXPECT_TRUE(listener
.WaitUntilSatisfied());
360 ExtensionTestMessageListener
listenerNotification("notification", false);
361 service()->FinalizeSpeakerModel();
362 EXPECT_TRUE(listenerNotification
.WaitUntilSatisfied());
365 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, OnHotwordTriggered
) {
366 // Trigger the pref registrar.
367 extensions::HotwordPrivateEventService::GetFactoryInstance();
368 ExtensionTestMessageListener
listener("ready", false);
370 LoadExtensionAsComponent(test_data_dir_
.AppendASCII(
371 "onHotwordTriggered")));
372 EXPECT_TRUE(listener
.WaitUntilSatisfied());
374 ExtensionTestMessageListener
listenerNotification("notification", false);
375 service()->NotifyHotwordTriggered();
376 EXPECT_TRUE(listenerNotification
.WaitUntilSatisfied());
379 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, OnDeleteSpeakerModel
) {
380 MockWebHistoryService
* web_history
= new MockWebHistoryService(profile());
381 MockAudioHistoryHandler
* handler
=
382 new MockAudioHistoryHandler(profile(), web_history
);
383 service()->SetAudioHistoryHandler(handler
);
384 web_history
->SetExpectedValue(false);
385 profile()->GetPrefs()->SetBoolean(prefs::kHotwordAlwaysOnSearchEnabled
, true);
387 // Trigger the pref registrar.
388 extensions::HotwordPrivateEventService::GetFactoryInstance();
389 ExtensionTestMessageListener
listener("ready", false);
391 LoadExtensionAsComponent(test_data_dir_
.AppendASCII(
392 "onDeleteSpeakerModel")));
393 EXPECT_TRUE(listener
.WaitUntilSatisfied());
395 ExtensionTestMessageListener
listenerNotification("notification", false);
396 EXPECT_TRUE(listenerNotification
.WaitUntilSatisfied());
399 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, OnSpeakerModelExists
) {
400 extensions::HotwordPrivateEventService::GetFactoryInstance();
401 ExtensionTestMessageListener
listener("ready", false);
403 LoadExtensionAsComponent(test_data_dir_
.AppendASCII(
404 "onSpeakerModelExists")));
405 EXPECT_TRUE(listener
.WaitUntilSatisfied());
407 service()->OptIntoHotwording(HotwordService::HOTWORD_ONLY
);
409 ExtensionTestMessageListener
listenerNotification("notification", false);
410 EXPECT_TRUE(listenerNotification
.WaitUntilSatisfied());
413 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, SpeakerModelExistsResult
) {
414 EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
415 prefs::kHotwordAlwaysOnSearchEnabled
));
417 ExtensionTestMessageListener
listenerTrue("ready", false);
418 ASSERT_TRUE(RunComponentExtensionTest(
419 "speakerModelExistsResultTrue")) << message_
;
420 EXPECT_TRUE(listenerTrue
.WaitUntilSatisfied());
421 EXPECT_TRUE(profile()->GetPrefs()->GetBoolean(
422 prefs::kHotwordAlwaysOnSearchEnabled
));
424 PrefService
* prefs
= profile()->GetPrefs();
425 prefs
->SetBoolean(prefs::kHotwordAlwaysOnSearchEnabled
, false);
426 ExtensionTestMessageListener
listenerFalse("ready", false);
427 ASSERT_TRUE(RunComponentExtensionTest(
428 "speakerModelExistsResultFalse")) << message_
;
429 EXPECT_TRUE(listenerFalse
.WaitUntilSatisfied());
430 EXPECT_FALSE(profile()->GetPrefs()->GetBoolean(
431 prefs::kHotwordAlwaysOnSearchEnabled
));
434 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, Training
) {
435 EXPECT_FALSE(service()->IsTraining());
437 ExtensionTestMessageListener
listenerTrue("start training", false);
438 ASSERT_TRUE(RunComponentExtensionTest("startTraining")) << message_
;
439 EXPECT_TRUE(listenerTrue
.WaitUntilSatisfied());
440 EXPECT_TRUE(service()->IsTraining());
442 ExtensionTestMessageListener
listenerFalse("stop training", false);
443 ASSERT_TRUE(RunComponentExtensionTest("stopTraining")) << message_
;
444 EXPECT_TRUE(listenerFalse
.WaitUntilSatisfied());
445 EXPECT_FALSE(service()->IsTraining());
448 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, OnSpeakerModelSaved
) {
449 extensions::HotwordPrivateEventService::GetFactoryInstance();
450 ExtensionTestMessageListener
listener("ready", false);
452 LoadExtensionAsComponent(test_data_dir_
.AppendASCII(
453 "onSpeakerModelSaved")));
454 EXPECT_TRUE(listener
.WaitUntilSatisfied());
456 ExtensionTestMessageListener
listenerNotification("notification", false);
457 EXPECT_TRUE(listenerNotification
.WaitUntilSatisfied());
460 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, NotifySpeakerModelSaved
) {
461 ExtensionTestMessageListener
listener("speaker model saved", false);
463 RunComponentExtensionTest("notifySpeakerModelSaved")) << message_
;
464 EXPECT_TRUE(listener
.WaitUntilSatisfied());
467 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, AudioHistory
) {
468 MockWebHistoryService
* web_history
= new MockWebHistoryService(profile());
469 MockAudioHistoryHandler
* handler
=
470 new MockAudioHistoryHandler(profile(), web_history
);
471 service()->SetAudioHistoryHandler(handler
);
472 web_history
->SetExpectedValue(true);
474 ExtensionTestMessageListener
setListenerT("set AH: true success", false);
475 ExtensionTestMessageListener
setListenerF("set AH: false success", false);
476 ExtensionTestMessageListener
getListener("get AH: true success", false);
478 ASSERT_TRUE(RunComponentExtensionTest("audioHistory")) << message_
;
480 EXPECT_TRUE(setListenerT
.WaitUntilSatisfied());
481 EXPECT_TRUE(setListenerF
.WaitUntilSatisfied());
482 EXPECT_TRUE(getListener
.WaitUntilSatisfied());
484 web_history
->SetExpectedValue(false);
486 ExtensionTestMessageListener
setListenerT2("set AH: true success", false);
487 ExtensionTestMessageListener
setListenerF2("set AH: false success", false);
488 ExtensionTestMessageListener
getListener2("get AH: false success", false);
490 ASSERT_TRUE(RunComponentExtensionTest("audioHistory")) << message_
;
492 EXPECT_TRUE(setListenerT2
.WaitUntilSatisfied());
493 EXPECT_TRUE(setListenerF2
.WaitUntilSatisfied());
494 EXPECT_TRUE(getListener2
.WaitUntilSatisfied());
497 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, AudioHistoryNoWebHistory
) {
498 MockAudioHistoryHandler
* handler
=
499 new MockAudioHistoryHandler(profile(), nullptr);
500 service()->SetAudioHistoryHandler(handler
);
502 // Set an initial value for the audio logging pref.
503 PrefService
* prefs
= profile()->GetPrefs();
504 prefs
->SetBoolean(prefs::kHotwordAudioLoggingEnabled
, true);
506 ExtensionTestMessageListener
setListenerT("set AH: true failure", false);
507 ExtensionTestMessageListener
setListenerF("set AH: true failure", false);
508 ExtensionTestMessageListener
getListener("get AH: true failure", false);
510 ASSERT_TRUE(RunComponentExtensionTest("audioHistory")) << message_
;
512 EXPECT_TRUE(setListenerT
.WaitUntilSatisfied());
513 EXPECT_TRUE(setListenerF
.WaitUntilSatisfied());
514 EXPECT_TRUE(getListener
.WaitUntilSatisfied());
517 IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest
, AudioHistoryWebHistoryFailure
) {
518 MockWebHistoryService
* web_history
= new MockWebHistoryService(profile());
519 MockAudioHistoryHandler
* handler
=
520 new MockAudioHistoryHandler(profile(), web_history
);
521 service()->SetAudioHistoryHandler(handler
);
522 web_history
->SetFailureState();
523 // It shouldn't matter if this is set to true. GetAduioHistoryEnabled should
524 // still return false.
525 web_history
->SetExpectedValue(true);
527 ExtensionTestMessageListener
setListenerT("set AH: false failure", false);
528 ExtensionTestMessageListener
setListenerF("set AH: false failure", false);
529 ExtensionTestMessageListener
getListener("get AH: false failure", false);
531 ASSERT_TRUE(RunComponentExtensionTest("audioHistory")) << message_
;
533 EXPECT_TRUE(setListenerT
.WaitUntilSatisfied());
534 EXPECT_TRUE(setListenerF
.WaitUntilSatisfied());
535 EXPECT_TRUE(getListener
.WaitUntilSatisfied());