1 // Copyright (c) 2011 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 "chrome/browser/chromeos/customization_document.h"
6
7 #include "base/message_loop/message_loop.h"
8 #include "base/prefs/testing_pref_service.h"
9 #include "base/run_loop.h"
10 #include "base/strings/stringprintf.h"
11 #include "chrome/browser/chromeos/net/network_portal_detector_test_impl.h"
12 #include "chrome/browser/extensions/external_provider_impl.h"
13 #include "chrome/browser/prefs/browser_prefs.h"
14 #include "chrome/browser/prefs/pref_service_mock_factory.h"
15 #include "chrome/browser/prefs/pref_service_syncable.h"
16 #include "chrome/browser/ui/app_list/app_list_syncable_service.h"
17 #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
18 #include "chrome/test/base/testing_browser_process.h"
19 #include "chrome/test/base/testing_profile.h"
20 #include "chromeos/dbus/dbus_thread_manager.h"
21 #include "chromeos/network/network_handler.h"
22 #include "chromeos/network/network_state.h"
23 #include "chromeos/network/network_state_handler.h"
24 #include "chromeos/system/mock_statistics_provider.h"
25 #include "components/pref_registry/pref_registry_syncable.h"
26 #include "content/public/test/test_browser_thread_bundle.h"
27 #include "extensions/common/extension.h"
28 #include "extensions/common/manifest.h"
29 #include "net/http/http_response_headers.h"
30 #include "net/http/http_status_code.h"
31 #include "net/url_request/test_url_fetcher_factory.h"
32 #include "net/url_request/url_request_status.h"
33 #include "testing/gmock/include/gmock/gmock.h"
34 #include "testing/gtest/include/gtest/gtest.h"
35
36 using ::testing::Exactly;
37 using ::testing::Invoke;
38 using ::testing::Mock;
39 using ::testing::_;
40
41 namespace {
42
43 const char kGoodStartupManifest[] =
44 "{"
45 " \"version\": \"1.0\","
46 " \"initial_locale\" : \"en-US\","
47 " \"initial_timezone\" : \"US/Pacific\","
48 " \"keyboard_layout\" : \"xkb:us::eng\","
49 " \"setup_content\" : {"
50 " \"en-US\" : {"
51 " \"eula_page\" : \"file:///opt/oem/eula/en-US/eula.html\","
52 " },"
53 " \"ru-RU\" : {"
54 " \"eula_page\" : \"file:///opt/oem/eula/ru-RU/eula.html\","
55 " },"
56 " \"default\" : {"
57 " \"eula_page\" : \"file:///opt/oem/eula/en/eula.html\","
58 " },"
59 " },"
60 " \"hwid_map\" : ["
61 " {"
62 " \"hwid_mask\": \"ZGA*34\","
63 " \"initial_locale\" : \"ja\","
64 " \"initial_timezone\" : \"Asia/Tokyo\","
65 " \"keyboard_layout\" : \"mozc-jp\","
66 " },"
67 " {"
68 " \"hwid_mask\": \"Mario 1?3*\","
69 " \"initial_locale\" : \"ru-RU\","
70 " \"initial_timezone\" : \"Europe/Moscow\","
71 " \"keyboard_layout\" : \"xkb:ru::rus\","
72 " },"
73 " ],"
74 "}";
75
76 const char kBadManifest[] = "{\"version\": \"1\"}";
77
78 const char kGoodServicesManifest[] =
79 "{"
80 " \"version\": \"1.0\","
81 " \"default_apps\": [\n"
82 " \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n"
83 " \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"\n"
84 " ],\n"
85 " \"localized_content\": {\n"
86 " \"en-US\": {\n"
87 " \"default_apps_folder_name\": \"EN-US OEM Name\"\n"
88 " },\n"
89 " \"en\": {\n"
90 " \"default_apps_folder_name\": \"EN OEM Name\"\n"
91 " },\n"
92 " \"default\": {\n"
93 " \"default_apps_folder_name\": \"Default OEM Name\"\n"
94 " }\n"
95 " }\n"
96 "}";
97
98 const char kDummyCustomizationID[] = "test-dummy";
99
100 } // anonymous namespace
101
102 namespace chromeos {
103
104 using ::testing::_;
105 using ::testing::DoAll;
106 using ::testing::NotNull;
107 using ::testing::Return;
108 using ::testing::SetArgumentPointee;
109
TEST(StartupCustomizationDocumentTest,Basic)110 TEST(StartupCustomizationDocumentTest, Basic) {
111 system::MockStatisticsProvider mock_statistics_provider;
112 EXPECT_CALL(mock_statistics_provider, GetMachineStatistic(_, NotNull()))
113 .WillRepeatedly(Return(false));
114 EXPECT_CALL(mock_statistics_provider,
115 GetMachineStatistic(std::string("hardware_class"), NotNull()))
116 .WillOnce(DoAll(SetArgumentPointee<1>(std::string("Mario 12345")),
117 Return(true)));
118 StartupCustomizationDocument customization(&mock_statistics_provider,
119 kGoodStartupManifest);
120 EXPECT_EQ("ru-RU", customization.initial_locale());
121 EXPECT_EQ("Europe/Moscow", customization.initial_timezone());
122 EXPECT_EQ("xkb:ru::rus", customization.keyboard_layout());
123
124 EXPECT_EQ("file:///opt/oem/eula/en-US/eula.html",
125 customization.GetEULAPage("en-US"));
126 EXPECT_EQ("file:///opt/oem/eula/ru-RU/eula.html",
127 customization.GetEULAPage("ru-RU"));
128 EXPECT_EQ("file:///opt/oem/eula/en/eula.html",
129 customization.GetEULAPage("ja"));
130 }
131
TEST(StartupCustomizationDocumentTest,VPD)132 TEST(StartupCustomizationDocumentTest, VPD) {
133 system::MockStatisticsProvider mock_statistics_provider;
134 EXPECT_CALL(mock_statistics_provider,
135 GetMachineStatistic(std::string("hardware_class"), NotNull()))
136 .WillOnce(DoAll(SetArgumentPointee<1>(std::string("Mario 12345")),
137 Return(true)));
138 EXPECT_CALL(mock_statistics_provider,
139 GetMachineStatistic(std::string("initial_locale"), NotNull()))
140 .WillOnce(DoAll(SetArgumentPointee<1>(std::string("ja")),
141 Return(true)));
142 EXPECT_CALL(mock_statistics_provider,
143 GetMachineStatistic(std::string("initial_timezone"), NotNull()))
144 .WillOnce(DoAll(SetArgumentPointee<1>(std::string("Asia/Tokyo")),
145 Return(true)));
146 EXPECT_CALL(mock_statistics_provider,
147 GetMachineStatistic(std::string("keyboard_layout"), NotNull()))
148 .WillOnce(DoAll(SetArgumentPointee<1>(std::string("mozc-jp")),
149 Return(true)));
150 StartupCustomizationDocument customization(&mock_statistics_provider,
151 kGoodStartupManifest);
152 EXPECT_TRUE(customization.IsReady());
153 EXPECT_EQ("ja", customization.initial_locale());
154 EXPECT_EQ("Asia/Tokyo", customization.initial_timezone());
155 EXPECT_EQ("mozc-jp", customization.keyboard_layout());
156 }
157
TEST(StartupCustomizationDocumentTest,BadManifest)158 TEST(StartupCustomizationDocumentTest, BadManifest) {
159 system::MockStatisticsProvider mock_statistics_provider;
160 StartupCustomizationDocument customization(&mock_statistics_provider,
161 kBadManifest);
162 EXPECT_FALSE(customization.IsReady());
163 }
164
165 class TestURLFetcherCallback {
166 public:
CreateURLFetcher(const GURL & url,net::URLFetcherDelegate * d,const std::string & response_data,net::HttpStatusCode response_code,net::URLRequestStatus::Status status)167 scoped_ptr<net::FakeURLFetcher> CreateURLFetcher(
168 const GURL& url,
169 net::URLFetcherDelegate* d,
170 const std::string& response_data,
171 net::HttpStatusCode response_code,
172 net::URLRequestStatus::Status status) {
173 scoped_ptr<net::FakeURLFetcher> fetcher(
174 new net::FakeURLFetcher(url, d, response_data, response_code, status));
175 OnRequestCreate(url, fetcher.get());
176 return fetcher.Pass();
177 }
178 MOCK_METHOD2(OnRequestCreate,
179 void(const GURL&, net::FakeURLFetcher*));
180 };
181
AddMimeHeader(const GURL & url,net::FakeURLFetcher * fetcher)182 void AddMimeHeader(const GURL& url, net::FakeURLFetcher* fetcher) {
183 scoped_refptr<net::HttpResponseHeaders> download_headers =
184 new net::HttpResponseHeaders("");
185 download_headers->AddHeader("Content-Type: application/json");
186 fetcher->set_response_headers(download_headers);
187 }
188
189 class MockExternalProviderVisitor
190 : public extensions::ExternalProviderInterface::VisitorInterface {
191 public:
MockExternalProviderVisitor()192 MockExternalProviderVisitor() {}
193
194 MOCK_METHOD6(OnExternalExtensionFileFound,
195 bool(const std::string&,
196 const base::Version*,
197 const base::FilePath&,
198 extensions::Manifest::Location,
199 int,
200 bool));
201 MOCK_METHOD6(OnExternalExtensionUpdateUrlFound,
202 bool(const std::string&,
203 const std::string&,
204 const GURL&,
205 extensions::Manifest::Location,
206 int,
207 bool));
208 MOCK_METHOD1(OnExternalProviderReady,
209 void(const extensions::ExternalProviderInterface* provider));
210 };
211
212 class ServicesCustomizationDocumentTest : public testing::Test {
213 protected:
ServicesCustomizationDocumentTest()214 ServicesCustomizationDocumentTest()
215 : factory_(NULL,
216 base::Bind(&TestURLFetcherCallback::CreateURLFetcher,
217 base::Unretained(&url_callback_))) {
218 }
219
220 // testing::Test:
SetUp()221 virtual void SetUp() OVERRIDE {
222 ServicesCustomizationDocument::InitializeForTesting();
223
224 EXPECT_CALL(mock_statistics_provider_, GetMachineStatistic(_, NotNull()))
225 .WillRepeatedly(Return(false));
226 chromeos::system::StatisticsProvider::SetTestProvider(
227 &mock_statistics_provider_);
228
229 DBusThreadManager::Initialize();
230 NetworkHandler::Initialize();
231 RunUntilIdle();
232 const NetworkState* default_network =
233 NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
234 std::string default_network_path =
235 default_network ? default_network->path() : "";
236
237 NetworkPortalDetector::InitializeForTesting(&network_portal_detector_);
238 NetworkPortalDetector::CaptivePortalState online_state;
239 online_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE;
240 online_state.response_code = 204;
241 std::string guid =
242 default_network ? default_network->guid() : std::string();
243 network_portal_detector_.SetDefaultNetworkForTesting(guid);
244 if (!guid.empty()) {
245 network_portal_detector_.SetDetectionResultsForTesting(
246 guid, online_state);
247 }
248
249 TestingBrowserProcess::GetGlobal()->SetLocalState(&local_state_);
250 ServicesCustomizationDocument::RegisterPrefs(local_state_.registry());
251 }
252
TearDown()253 virtual void TearDown() OVERRIDE {
254 TestingBrowserProcess::GetGlobal()->SetLocalState(NULL);
255 NetworkHandler::Shutdown();
256 DBusThreadManager::Shutdown();
257 NetworkPortalDetector::InitializeForTesting(NULL);
258 chromeos::system::StatisticsProvider::SetTestProvider(NULL);
259
260 ServicesCustomizationDocument::ShutdownForTesting();
261 }
262
RunUntilIdle()263 void RunUntilIdle() {
264 base::RunLoop().RunUntilIdle();
265 }
266
AddCustomizationIdToVp(const std::string & id)267 void AddCustomizationIdToVp(const std::string& id) {
268 EXPECT_CALL(mock_statistics_provider_,
269 GetMachineStatistic(system::kCustomizationIdKey, NotNull()))
270 .WillOnce(DoAll(SetArgumentPointee<1>(id),
271 Return(true)));
272 }
273
AddExpectedManifest(const std::string & id,const std::string & manifest)274 void AddExpectedManifest(const std::string& id,
275 const std::string& manifest) {
276 GURL url(base::StringPrintf(ServicesCustomizationDocument::kManifestUrl,
277 id.c_str()));
278 factory_.SetFakeResponse(url,
279 manifest,
280 net::HTTP_OK,
281 net::URLRequestStatus::SUCCESS);
282 EXPECT_CALL(url_callback_, OnRequestCreate(url, _))
283 .Times(Exactly(1))
284 .WillRepeatedly(Invoke(AddMimeHeader));
285 }
286
AddManifestNotFound(const std::string & id)287 void AddManifestNotFound(const std::string& id) {
288 GURL url(base::StringPrintf(ServicesCustomizationDocument::kManifestUrl,
289 id.c_str()));
290 factory_.SetFakeResponse(url,
291 std::string(),
292 net::HTTP_NOT_FOUND,
293 net::URLRequestStatus::SUCCESS);
294 EXPECT_CALL(url_callback_, OnRequestCreate(url, _))
295 .Times(Exactly(1))
296 .WillRepeatedly(Invoke(AddMimeHeader));
297 }
298
CreateProfile()299 scoped_ptr<TestingProfile> CreateProfile() {
300 TestingProfile::Builder profile_builder;
301 PrefServiceMockFactory factory;
302 scoped_refptr<user_prefs::PrefRegistrySyncable> registry(
303 new user_prefs::PrefRegistrySyncable);
304 scoped_ptr<PrefServiceSyncable> prefs(
305 factory.CreateSyncable(registry.get()));
306 chrome::RegisterUserProfilePrefs(registry.get());
307 profile_builder.SetPrefService(prefs.Pass());
308 return profile_builder.Build();
309 }
310
311 private:
312 system::MockStatisticsProvider mock_statistics_provider_;
313 content::TestBrowserThreadBundle thread_bundle_;
314 TestingPrefServiceSimple local_state_;
315 TestURLFetcherCallback url_callback_;
316 net::FakeURLFetcherFactory factory_;
317 NetworkPortalDetectorTestImpl network_portal_detector_;
318 };
319
TEST_F(ServicesCustomizationDocumentTest,Basic)320 TEST_F(ServicesCustomizationDocumentTest, Basic) {
321 AddCustomizationIdToVp(kDummyCustomizationID);
322 AddExpectedManifest(kDummyCustomizationID, kGoodServicesManifest);
323
324 ServicesCustomizationDocument* doc =
325 ServicesCustomizationDocument::GetInstance();
326 EXPECT_FALSE(doc->IsReady());
327
328 doc->StartFetching();
329 RunUntilIdle();
330 EXPECT_TRUE(doc->IsReady());
331
332 GURL wallpaper_url;
333 EXPECT_FALSE(doc->GetDefaultWallpaperUrl(&wallpaper_url));
334 EXPECT_EQ("", wallpaper_url.spec());
335
336 std::vector<std::string> default_apps;
337 EXPECT_TRUE(doc->GetDefaultApps(&default_apps));
338 ASSERT_EQ(default_apps.size(), 2u);
339
340 EXPECT_EQ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", default_apps[0]);
341 EXPECT_EQ("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", default_apps[1]);
342
343 EXPECT_EQ("EN-US OEM Name", doc->GetOemAppsFolderName("en-US"));
344 EXPECT_EQ("EN OEM Name", doc->GetOemAppsFolderName("en"));
345 EXPECT_EQ("Default OEM Name", doc->GetOemAppsFolderName("ru"));
346 }
347
TEST_F(ServicesCustomizationDocumentTest,NoCustomizationIdInVpd)348 TEST_F(ServicesCustomizationDocumentTest, NoCustomizationIdInVpd) {
349 ServicesCustomizationDocument* doc =
350 ServicesCustomizationDocument::GetInstance();
351 EXPECT_FALSE(doc->IsReady());
352
353 scoped_ptr<TestingProfile> profile = CreateProfile();
354 extensions::ExternalLoader* loader = doc->CreateExternalLoader(profile.get());
355 EXPECT_TRUE(loader);
356
357 MockExternalProviderVisitor visitor;
358 scoped_ptr<extensions::ExternalProviderImpl> provider(
359 new extensions::ExternalProviderImpl(
360 &visitor,
361 loader,
362 profile.get(),
363 extensions::Manifest::EXTERNAL_PREF,
364 extensions::Manifest::EXTERNAL_PREF_DOWNLOAD,
365 extensions::Extension::FROM_WEBSTORE |
366 extensions::Extension::WAS_INSTALLED_BY_DEFAULT));
367
368 EXPECT_CALL(visitor, OnExternalExtensionFileFound(_, _, _, _, _, _))
369 .Times(0);
370 EXPECT_CALL(visitor, OnExternalExtensionUpdateUrlFound(_, _, _, _, _, _))
371 .Times(0);
372 EXPECT_CALL(visitor, OnExternalProviderReady(_))
373 .Times(1);
374
375 // Manually request a load.
376 RunUntilIdle();
377 loader->StartLoading();
378 Mock::VerifyAndClearExpectations(&visitor);
379
380 RunUntilIdle();
381 // Empty customization is used when there is no customization ID in VPD.
382 EXPECT_TRUE(doc->IsReady());
383 }
384
TEST_F(ServicesCustomizationDocumentTest,DefaultApps)385 TEST_F(ServicesCustomizationDocumentTest, DefaultApps) {
386 AddCustomizationIdToVp(kDummyCustomizationID);
387 AddExpectedManifest(kDummyCustomizationID, kGoodServicesManifest);
388
389 ServicesCustomizationDocument* doc =
390 ServicesCustomizationDocument::GetInstance();
391 EXPECT_FALSE(doc->IsReady());
392
393 scoped_ptr<TestingProfile> profile = CreateProfile();
394 extensions::ExternalLoader* loader = doc->CreateExternalLoader(profile.get());
395 EXPECT_TRUE(loader);
396
397 app_list::AppListSyncableServiceFactory::GetInstance()->
398 SetTestingFactoryAndUse(
399 profile.get(),
400 &app_list::AppListSyncableServiceFactory::BuildInstanceFor);
401
402 MockExternalProviderVisitor visitor;
403 scoped_ptr<extensions::ExternalProviderImpl> provider(
404 new extensions::ExternalProviderImpl(
405 &visitor,
406 loader,
407 profile.get(),
408 extensions::Manifest::EXTERNAL_PREF,
409 extensions::Manifest::EXTERNAL_PREF_DOWNLOAD,
410 extensions::Extension::FROM_WEBSTORE |
411 extensions::Extension::WAS_INSTALLED_BY_DEFAULT));
412
413 EXPECT_CALL(visitor, OnExternalExtensionFileFound(_, _, _, _, _, _))
414 .Times(0);
415 EXPECT_CALL(visitor, OnExternalExtensionUpdateUrlFound(_, _, _, _, _, _))
416 .Times(0);
417 EXPECT_CALL(visitor, OnExternalProviderReady(_))
418 .Times(1);
419
420 // Manually request a load.
421 loader->StartLoading();
422 Mock::VerifyAndClearExpectations(&visitor);
423
424 EXPECT_CALL(visitor, OnExternalExtensionFileFound(_, _, _, _, _, _))
425 .Times(0);
426 EXPECT_CALL(visitor, OnExternalExtensionUpdateUrlFound(_, _, _, _, _, _))
427 .Times(2);
428 EXPECT_CALL(visitor, OnExternalProviderReady(_))
429 .Times(1);
430
431 RunUntilIdle();
432 EXPECT_TRUE(doc->IsReady());
433
434 app_list::AppListSyncableService* service =
435 app_list::AppListSyncableServiceFactory::GetForProfile(profile.get());
436 ASSERT_TRUE(service);
437 EXPECT_EQ("EN OEM Name", service->GetOemFolderNameForTest());
438 }
439
TEST_F(ServicesCustomizationDocumentTest,CustomizationManifestNotFound)440 TEST_F(ServicesCustomizationDocumentTest, CustomizationManifestNotFound) {
441 AddCustomizationIdToVp(kDummyCustomizationID);
442 AddManifestNotFound(kDummyCustomizationID);
443
444 ServicesCustomizationDocument* doc =
445 ServicesCustomizationDocument::GetInstance();
446 EXPECT_FALSE(doc->IsReady());
447
448 scoped_ptr<TestingProfile> profile = CreateProfile();
449 extensions::ExternalLoader* loader = doc->CreateExternalLoader(profile.get());
450 EXPECT_TRUE(loader);
451
452 MockExternalProviderVisitor visitor;
453 scoped_ptr<extensions::ExternalProviderImpl> provider(
454 new extensions::ExternalProviderImpl(
455 &visitor,
456 loader,
457 profile.get(),
458 extensions::Manifest::EXTERNAL_PREF,
459 extensions::Manifest::EXTERNAL_PREF_DOWNLOAD,
460 extensions::Extension::FROM_WEBSTORE |
461 extensions::Extension::WAS_INSTALLED_BY_DEFAULT));
462
463 EXPECT_CALL(visitor, OnExternalExtensionFileFound(_, _, _, _, _, _))
464 .Times(0);
465 EXPECT_CALL(visitor, OnExternalExtensionUpdateUrlFound(_, _, _, _, _, _))
466 .Times(0);
467 EXPECT_CALL(visitor, OnExternalProviderReady(_))
468 .Times(1);
469
470 // Manually request a load.
471 loader->StartLoading();
472 Mock::VerifyAndClearExpectations(&visitor);
473
474 EXPECT_CALL(visitor, OnExternalExtensionFileFound(_, _, _, _, _, _))
475 .Times(0);
476 EXPECT_CALL(visitor, OnExternalExtensionUpdateUrlFound(_, _, _, _, _, _))
477 .Times(0);
478 EXPECT_CALL(visitor, OnExternalProviderReady(_))
479 .Times(1);
480
481 RunUntilIdle();
482 EXPECT_TRUE(doc->IsReady());
483 }
484
485 } // namespace chromeos
486