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.
4
5 #include "base/memory/scoped_ptr.h"
6 #include "base/metrics/field_trial.h"
7 #include "base/prefs/pref_service.h"
8 #include "chrome/browser/browser_process.h"
9 #include "chrome/browser/extensions/extension_service_test_base.h"
10 #include "chrome/browser/extensions/test_extension_service.h"
11 #include "chrome/browser/search/hotword_service.h"
12 #include "chrome/browser/search/hotword_service_factory.h"
13 #include "chrome/common/extensions/extension_constants.h"
14 #include "chrome/common/pref_names.h"
15 #include "chrome/test/base/testing_profile.h"
16 #include "content/public/test/test_browser_thread_bundle.h"
17 #include "extensions/browser/extension_system.h"
18 #include "extensions/common/extension.h"
19 #include "extensions/common/extension_builder.h"
20 #include "extensions/common/manifest.h"
21 #include "extensions/common/one_shot_event.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23
24 namespace {
25
26 class MockHotwordService : public HotwordService {
27 public:
MockHotwordService(Profile * profile)28 explicit MockHotwordService(Profile* profile)
29 : HotwordService(profile),
30 uninstall_count_(0) {
31 }
32
UninstallHotwordExtension(ExtensionService * extension_service)33 virtual bool UninstallHotwordExtension(
34 ExtensionService* extension_service) OVERRIDE {
35 uninstall_count_++;
36 return HotwordService::UninstallHotwordExtension(extension_service);
37 }
38
InstallHotwordExtensionFromWebstore()39 virtual void InstallHotwordExtensionFromWebstore() OVERRIDE{
40 scoped_ptr<base::DictionaryValue> manifest =
41 extensions::DictionaryBuilder()
42 .Set("name", "Hotword Test Extension")
43 .Set("version", "1.0")
44 .Set("manifest_version", 2)
45 .Build();
46 scoped_refptr<extensions::Extension> extension =
47 extensions::ExtensionBuilder().SetManifest(manifest.Pass())
48 .AddFlags(extensions::Extension::FROM_WEBSTORE
49 | extensions::Extension::WAS_INSTALLED_BY_DEFAULT)
50 .SetID(extension_misc::kHotwordExtensionId)
51 .SetLocation(extensions::Manifest::EXTERNAL_COMPONENT)
52 .Build();
53 ASSERT_TRUE(extension.get());
54 service_->OnExtensionInstalled(extension, syncer::StringOrdinal());
55 }
56
57
uninstall_count()58 int uninstall_count() { return uninstall_count_; }
59
SetExtensionService(ExtensionService * service)60 void SetExtensionService(ExtensionService* service) { service_ = service; }
61
extension_service()62 ExtensionService* extension_service() { return service_; }
63
64 private:
65 ExtensionService* service_;
66 int uninstall_count_;
67 };
68
BuildMockHotwordService(content::BrowserContext * context)69 KeyedService* BuildMockHotwordService(content::BrowserContext* context) {
70 return new MockHotwordService(static_cast<Profile*>(context));
71 }
72
73 } // namespace
74
75 class HotwordServiceTest : public extensions::ExtensionServiceTestBase {
76 protected:
HotwordServiceTest()77 HotwordServiceTest() : field_trial_list_(NULL) {}
~HotwordServiceTest()78 virtual ~HotwordServiceTest() {}
79
SetApplicationLocale(Profile * profile,const std::string & new_locale)80 void SetApplicationLocale(Profile* profile, const std::string& new_locale) {
81 #if defined(OS_CHROMEOS)
82 // On ChromeOS locale is per-profile.
83 profile->GetPrefs()->SetString(prefs::kApplicationLocale, new_locale);
84 #else
85 g_browser_process->SetApplicationLocale(new_locale);
86 #endif
87 }
88
89 private:
90 base::FieldTrialList field_trial_list_;
91 };
92
TEST_F(HotwordServiceTest,IsHotwordAllowedBadFieldTrial)93 TEST_F(HotwordServiceTest, IsHotwordAllowedBadFieldTrial) {
94 TestingProfile::Builder profile_builder;
95 TestingProfile::Builder otr_profile_builder;
96 otr_profile_builder.SetIncognito();
97 scoped_ptr<TestingProfile> profile = profile_builder.Build();
98 scoped_ptr<TestingProfile> otr_profile = otr_profile_builder.Build();
99
100 HotwordServiceFactory* hotword_service_factory =
101 HotwordServiceFactory::GetInstance();
102
103 // Check that the service exists so that a NULL service be ruled out in
104 // following tests.
105 HotwordService* hotword_service =
106 hotword_service_factory->GetForProfile(profile.get());
107 EXPECT_TRUE(hotword_service != NULL);
108
109 // When the field trial is empty or Disabled, it should not be allowed.
110 std::string group = base::FieldTrialList::FindFullName(
111 hotword_internal::kHotwordFieldTrialName);
112 EXPECT_TRUE(group.empty());
113 EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(profile.get()));
114
115 ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
116 hotword_internal::kHotwordFieldTrialName,
117 hotword_internal::kHotwordFieldTrialDisabledGroupName));
118 group = base::FieldTrialList::FindFullName(
119 hotword_internal::kHotwordFieldTrialName);
120 EXPECT_TRUE(group ==hotword_internal::kHotwordFieldTrialDisabledGroupName);
121 EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(profile.get()));
122
123 // Set a valid locale with invalid field trial to be sure it is
124 // still false.
125 SetApplicationLocale(static_cast<Profile*>(profile.get()), "en");
126 EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(profile.get()));
127
128 // Test that incognito returns false as well.
129 EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(otr_profile.get()));
130 }
131
TEST_F(HotwordServiceTest,IsHotwordAllowedLocale)132 TEST_F(HotwordServiceTest, IsHotwordAllowedLocale) {
133 TestingProfile::Builder profile_builder;
134 TestingProfile::Builder otr_profile_builder;
135 otr_profile_builder.SetIncognito();
136 scoped_ptr<TestingProfile> profile = profile_builder.Build();
137 scoped_ptr<TestingProfile> otr_profile = otr_profile_builder.Build();
138
139 HotwordServiceFactory* hotword_service_factory =
140 HotwordServiceFactory::GetInstance();
141
142 // Check that the service exists so that a NULL service be ruled out in
143 // following tests.
144 HotwordService* hotword_service =
145 hotword_service_factory->GetForProfile(profile.get());
146 EXPECT_TRUE(hotword_service != NULL);
147
148 // Set the field trial to a valid one.
149 ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
150 hotword_internal::kHotwordFieldTrialName, "Good"));
151
152 // Set the language to an invalid one.
153 SetApplicationLocale(static_cast<Profile*>(profile.get()), "non-valid");
154 EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(profile.get()));
155
156 // Now with valid locales it should be fine.
157 SetApplicationLocale(static_cast<Profile*>(profile.get()), "en");
158 EXPECT_TRUE(HotwordServiceFactory::IsHotwordAllowed(profile.get()));
159 SetApplicationLocale(static_cast<Profile*>(profile.get()), "en-US");
160 EXPECT_TRUE(HotwordServiceFactory::IsHotwordAllowed(profile.get()));
161 SetApplicationLocale(static_cast<Profile*>(profile.get()), "en_us");
162 EXPECT_TRUE(HotwordServiceFactory::IsHotwordAllowed(profile.get()));
163 SetApplicationLocale(static_cast<Profile*>(profile.get()), "de_DE");
164 EXPECT_TRUE(HotwordServiceFactory::IsHotwordAllowed(profile.get()));
165 SetApplicationLocale(static_cast<Profile*>(profile.get()), "fr_fr");
166 EXPECT_TRUE(HotwordServiceFactory::IsHotwordAllowed(profile.get()));
167
168 // Test that incognito even with a valid locale and valid field trial
169 // still returns false.
170 SetApplicationLocale(static_cast<Profile*>(otr_profile.get()), "en");
171 EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(otr_profile.get()));
172 }
173
TEST_F(HotwordServiceTest,AudioLoggingPrefSetCorrectly)174 TEST_F(HotwordServiceTest, AudioLoggingPrefSetCorrectly) {
175 TestingProfile::Builder profile_builder;
176 scoped_ptr<TestingProfile> profile = profile_builder.Build();
177
178 HotwordServiceFactory* hotword_service_factory =
179 HotwordServiceFactory::GetInstance();
180 HotwordService* hotword_service =
181 hotword_service_factory->GetForProfile(profile.get());
182 EXPECT_TRUE(hotword_service != NULL);
183
184 // If it's a fresh profile, although the default value is true,
185 // it should return false if the preference has never been set.
186 EXPECT_FALSE(hotword_service->IsOptedIntoAudioLogging());
187 }
188
TEST_F(HotwordServiceTest,ShouldReinstallExtension)189 TEST_F(HotwordServiceTest, ShouldReinstallExtension) {
190 // Set the field trial to a valid one.
191 ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
192 hotword_internal::kHotwordFieldTrialName, "Install"));
193
194 InitializeEmptyExtensionService();
195
196 HotwordServiceFactory* hotword_service_factory =
197 HotwordServiceFactory::GetInstance();
198
199 MockHotwordService* hotword_service = static_cast<MockHotwordService*>(
200 hotword_service_factory->SetTestingFactoryAndUse(
201 profile(), BuildMockHotwordService));
202 EXPECT_TRUE(hotword_service != NULL);
203
204 // If no locale has been set, no reason to uninstall.
205 EXPECT_FALSE(hotword_service->ShouldReinstallHotwordExtension());
206
207 SetApplicationLocale(profile(), "en");
208 hotword_service->SetPreviousLanguagePref();
209
210 // Now a locale is set, but it hasn't changed.
211 EXPECT_FALSE(hotword_service->ShouldReinstallHotwordExtension());
212
213 SetApplicationLocale(profile(), "fr_fr");
214
215 // Now it's a different locale so it should uninstall.
216 EXPECT_TRUE(hotword_service->ShouldReinstallHotwordExtension());
217 }
218
TEST_F(HotwordServiceTest,PreviousLanguageSetOnInstall)219 TEST_F(HotwordServiceTest, PreviousLanguageSetOnInstall) {
220 // Set the field trial to a valid one.
221 ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
222 hotword_internal::kHotwordFieldTrialName, "Install"));
223
224 InitializeEmptyExtensionService();
225 service_->Init();
226
227 HotwordServiceFactory* hotword_service_factory =
228 HotwordServiceFactory::GetInstance();
229
230 MockHotwordService* hotword_service = static_cast<MockHotwordService*>(
231 hotword_service_factory->SetTestingFactoryAndUse(
232 profile(), BuildMockHotwordService));
233 EXPECT_TRUE(hotword_service != NULL);
234 hotword_service->SetExtensionService(service());
235
236 // If no locale has been set, no reason to uninstall.
237 EXPECT_FALSE(hotword_service->ShouldReinstallHotwordExtension());
238
239 SetApplicationLocale(profile(), "test_locale");
240
241 hotword_service->InstallHotwordExtensionFromWebstore();
242 base::MessageLoop::current()->RunUntilIdle();
243
244 EXPECT_EQ("test_locale",
245 profile()->GetPrefs()->GetString(prefs::kHotwordPreviousLanguage));
246 }
247
TEST_F(HotwordServiceTest,UninstallReinstallTriggeredCorrectly)248 TEST_F(HotwordServiceTest, UninstallReinstallTriggeredCorrectly) {
249 // Set the field trial to a valid one.
250 ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
251 hotword_internal::kHotwordFieldTrialName, "Install"));
252
253 InitializeEmptyExtensionService();
254 service_->Init();
255
256 HotwordServiceFactory* hotword_service_factory =
257 HotwordServiceFactory::GetInstance();
258
259 MockHotwordService* hotword_service = static_cast<MockHotwordService*>(
260 hotword_service_factory->SetTestingFactoryAndUse(
261 profile(), BuildMockHotwordService));
262 EXPECT_TRUE(hotword_service != NULL);
263 hotword_service->SetExtensionService(service());
264
265 // Initialize the locale to "en".
266 SetApplicationLocale(profile(), "en");
267
268 // The previous locale should not be set. No reason to uninstall.
269 EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension());
270
271 // Do an initial installation.
272 hotword_service->InstallHotwordExtensionFromWebstore();
273 base::MessageLoop::current()->RunUntilIdle();
274 EXPECT_EQ("en",
275 profile()->GetPrefs()->GetString(prefs::kHotwordPreviousLanguage));
276
277 // Verify the extension is installed but disabled.
278 EXPECT_EQ(1U, registry()->disabled_extensions().size());
279 EXPECT_TRUE(registry()->disabled_extensions().Contains(
280 extension_misc::kHotwordExtensionId));
281
282 // The previous locale should be set but should match the current
283 // locale. No reason to uninstall.
284 EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension());
285
286 // Switch the locale to a valid but different one.
287 SetApplicationLocale(profile(), "fr_fr");
288 EXPECT_TRUE(HotwordServiceFactory::IsHotwordAllowed(profile()));
289
290 // Different but valid locale so expect uninstall.
291 EXPECT_TRUE(hotword_service->MaybeReinstallHotwordExtension());
292 EXPECT_EQ(1, hotword_service->uninstall_count());
293 EXPECT_EQ("fr_fr",
294 profile()->GetPrefs()->GetString(prefs::kHotwordPreviousLanguage));
295
296 // Verify the extension is installed. It's still disabled.
297 EXPECT_TRUE(registry()->disabled_extensions().Contains(
298 extension_misc::kHotwordExtensionId));
299
300 // Switch the locale to an invalid one.
301 SetApplicationLocale(profile(), "invalid");
302 EXPECT_FALSE(HotwordServiceFactory::IsHotwordAllowed(profile()));
303 EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension());
304 EXPECT_EQ("fr_fr",
305 profile()->GetPrefs()->GetString(prefs::kHotwordPreviousLanguage));
306
307 // If the locale is set back to the last valid one, then an uninstall-install
308 // shouldn't be needed.
309 SetApplicationLocale(profile(), "fr_fr");
310 EXPECT_TRUE(HotwordServiceFactory::IsHotwordAllowed(profile()));
311 EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension());
312 EXPECT_EQ(1, hotword_service->uninstall_count()); // no change
313 }
314