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 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 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 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: 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 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: 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: 214 ServicesCustomizationDocumentTest() 215 : factory_(NULL, 216 base::Bind(&TestURLFetcherCallback::CreateURLFetcher, 217 base::Unretained(&url_callback_))) { 218 } 219 220 // testing::Test: 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::InitializeWithStub(); 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 network_portal_detector_.SetDefaultNetworkPathForTesting( 242 default_network_path, 243 default_network ? default_network->guid() : ""); 244 network_portal_detector_.SetDetectionResultsForTesting( 245 default_network_path, online_state); 246 247 TestingBrowserProcess::GetGlobal()->SetLocalState(&local_state_); 248 ServicesCustomizationDocument::RegisterPrefs(local_state_.registry()); 249 } 250 251 virtual void TearDown() OVERRIDE { 252 TestingBrowserProcess::GetGlobal()->SetLocalState(NULL); 253 NetworkHandler::Shutdown(); 254 DBusThreadManager::Shutdown(); 255 NetworkPortalDetector::InitializeForTesting(NULL); 256 chromeos::system::StatisticsProvider::SetTestProvider(NULL); 257 258 ServicesCustomizationDocument::ShutdownForTesting(); 259 } 260 261 void RunUntilIdle() { 262 base::RunLoop().RunUntilIdle(); 263 } 264 265 void AddCustomizationIdToVp(const std::string& id) { 266 EXPECT_CALL(mock_statistics_provider_, 267 GetMachineStatistic(system::kCustomizationIdKey, NotNull())) 268 .WillOnce(DoAll(SetArgumentPointee<1>(id), 269 Return(true))); 270 } 271 272 void AddExpectedManifest(const std::string& id, 273 const std::string& manifest) { 274 GURL url(base::StringPrintf(ServicesCustomizationDocument::kManifestUrl, 275 id.c_str())); 276 factory_.SetFakeResponse(url, 277 manifest, 278 net::HTTP_OK, 279 net::URLRequestStatus::SUCCESS); 280 EXPECT_CALL(url_callback_, OnRequestCreate(url, _)) 281 .Times(Exactly(1)) 282 .WillRepeatedly(Invoke(AddMimeHeader)); 283 } 284 285 void AddManifestNotFound(const std::string& id) { 286 GURL url(base::StringPrintf(ServicesCustomizationDocument::kManifestUrl, 287 id.c_str())); 288 factory_.SetFakeResponse(url, 289 std::string(), 290 net::HTTP_NOT_FOUND, 291 net::URLRequestStatus::SUCCESS); 292 EXPECT_CALL(url_callback_, OnRequestCreate(url, _)) 293 .Times(Exactly(1)) 294 .WillRepeatedly(Invoke(AddMimeHeader)); 295 } 296 297 scoped_ptr<TestingProfile> CreateProfile() { 298 TestingProfile::Builder profile_builder; 299 PrefServiceMockFactory factory; 300 scoped_refptr<user_prefs::PrefRegistrySyncable> registry( 301 new user_prefs::PrefRegistrySyncable); 302 scoped_ptr<PrefServiceSyncable> prefs( 303 factory.CreateSyncable(registry.get())); 304 chrome::RegisterUserProfilePrefs(registry.get()); 305 profile_builder.SetPrefService(prefs.Pass()); 306 return profile_builder.Build(); 307 } 308 309 private: 310 system::MockStatisticsProvider mock_statistics_provider_; 311 content::TestBrowserThreadBundle thread_bundle_; 312 TestingPrefServiceSimple local_state_; 313 TestURLFetcherCallback url_callback_; 314 net::FakeURLFetcherFactory factory_; 315 NetworkPortalDetectorTestImpl network_portal_detector_; 316 }; 317 318 TEST_F(ServicesCustomizationDocumentTest, Basic) { 319 AddCustomizationIdToVp(kDummyCustomizationID); 320 AddExpectedManifest(kDummyCustomizationID, kGoodServicesManifest); 321 322 ServicesCustomizationDocument* doc = 323 ServicesCustomizationDocument::GetInstance(); 324 EXPECT_FALSE(doc->IsReady()); 325 326 doc->StartFetching(); 327 RunUntilIdle(); 328 EXPECT_TRUE(doc->IsReady()); 329 330 GURL wallpaper_url; 331 EXPECT_FALSE(doc->GetDefaultWallpaperUrl(&wallpaper_url)); 332 EXPECT_EQ("", wallpaper_url.spec()); 333 334 std::vector<std::string> default_apps; 335 EXPECT_TRUE(doc->GetDefaultApps(&default_apps)); 336 ASSERT_EQ(default_apps.size(), 2u); 337 338 EXPECT_EQ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", default_apps[0]); 339 EXPECT_EQ("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", default_apps[1]); 340 341 EXPECT_EQ("EN-US OEM Name", doc->GetOemAppsFolderName("en-US")); 342 EXPECT_EQ("EN OEM Name", doc->GetOemAppsFolderName("en")); 343 EXPECT_EQ("Default OEM Name", doc->GetOemAppsFolderName("ru")); 344 } 345 346 TEST_F(ServicesCustomizationDocumentTest, NoCustomizationIdInVpd) { 347 ServicesCustomizationDocument* doc = 348 ServicesCustomizationDocument::GetInstance(); 349 EXPECT_FALSE(doc->IsReady()); 350 351 scoped_ptr<TestingProfile> profile = CreateProfile(); 352 extensions::ExternalLoader* loader = doc->CreateExternalLoader(profile.get()); 353 EXPECT_TRUE(loader); 354 355 MockExternalProviderVisitor visitor; 356 scoped_ptr<extensions::ExternalProviderImpl> provider( 357 new extensions::ExternalProviderImpl( 358 &visitor, 359 loader, 360 profile.get(), 361 extensions::Manifest::EXTERNAL_PREF, 362 extensions::Manifest::EXTERNAL_PREF_DOWNLOAD, 363 extensions::Extension::FROM_WEBSTORE | 364 extensions::Extension::WAS_INSTALLED_BY_DEFAULT)); 365 366 EXPECT_CALL(visitor, OnExternalExtensionFileFound(_, _, _, _, _, _)) 367 .Times(0); 368 EXPECT_CALL(visitor, OnExternalExtensionUpdateUrlFound(_, _, _, _, _, _)) 369 .Times(0); 370 EXPECT_CALL(visitor, OnExternalProviderReady(_)) 371 .Times(1); 372 373 // Manually request a load. 374 RunUntilIdle(); 375 loader->StartLoading(); 376 Mock::VerifyAndClearExpectations(&visitor); 377 378 RunUntilIdle(); 379 // Empty customization is used when there is no customization ID in VPD. 380 EXPECT_TRUE(doc->IsReady()); 381 } 382 383 TEST_F(ServicesCustomizationDocumentTest, DefaultApps) { 384 AddCustomizationIdToVp(kDummyCustomizationID); 385 AddExpectedManifest(kDummyCustomizationID, kGoodServicesManifest); 386 387 ServicesCustomizationDocument* doc = 388 ServicesCustomizationDocument::GetInstance(); 389 EXPECT_FALSE(doc->IsReady()); 390 391 scoped_ptr<TestingProfile> profile = CreateProfile(); 392 extensions::ExternalLoader* loader = doc->CreateExternalLoader(profile.get()); 393 EXPECT_TRUE(loader); 394 395 app_list::AppListSyncableServiceFactory::GetInstance()-> 396 SetTestingFactoryAndUse( 397 profile.get(), 398 &app_list::AppListSyncableServiceFactory::BuildInstanceFor); 399 400 MockExternalProviderVisitor visitor; 401 scoped_ptr<extensions::ExternalProviderImpl> provider( 402 new extensions::ExternalProviderImpl( 403 &visitor, 404 loader, 405 profile.get(), 406 extensions::Manifest::EXTERNAL_PREF, 407 extensions::Manifest::EXTERNAL_PREF_DOWNLOAD, 408 extensions::Extension::FROM_WEBSTORE | 409 extensions::Extension::WAS_INSTALLED_BY_DEFAULT)); 410 411 EXPECT_CALL(visitor, OnExternalExtensionFileFound(_, _, _, _, _, _)) 412 .Times(0); 413 EXPECT_CALL(visitor, OnExternalExtensionUpdateUrlFound(_, _, _, _, _, _)) 414 .Times(0); 415 EXPECT_CALL(visitor, OnExternalProviderReady(_)) 416 .Times(1); 417 418 // Manually request a load. 419 loader->StartLoading(); 420 Mock::VerifyAndClearExpectations(&visitor); 421 422 EXPECT_CALL(visitor, OnExternalExtensionFileFound(_, _, _, _, _, _)) 423 .Times(0); 424 EXPECT_CALL(visitor, OnExternalExtensionUpdateUrlFound(_, _, _, _, _, _)) 425 .Times(2); 426 EXPECT_CALL(visitor, OnExternalProviderReady(_)) 427 .Times(1); 428 429 RunUntilIdle(); 430 EXPECT_TRUE(doc->IsReady()); 431 432 app_list::AppListSyncableService* service = 433 app_list::AppListSyncableServiceFactory::GetForProfile(profile.get()); 434 ASSERT_TRUE(service); 435 EXPECT_EQ("EN OEM Name", service->GetOemFolderNameForTest()); 436 } 437 438 TEST_F(ServicesCustomizationDocumentTest, CustomizationManifestNotFound) { 439 AddCustomizationIdToVp(kDummyCustomizationID); 440 AddManifestNotFound(kDummyCustomizationID); 441 442 ServicesCustomizationDocument* doc = 443 ServicesCustomizationDocument::GetInstance(); 444 EXPECT_FALSE(doc->IsReady()); 445 446 scoped_ptr<TestingProfile> profile = CreateProfile(); 447 extensions::ExternalLoader* loader = doc->CreateExternalLoader(profile.get()); 448 EXPECT_TRUE(loader); 449 450 MockExternalProviderVisitor visitor; 451 scoped_ptr<extensions::ExternalProviderImpl> provider( 452 new extensions::ExternalProviderImpl( 453 &visitor, 454 loader, 455 profile.get(), 456 extensions::Manifest::EXTERNAL_PREF, 457 extensions::Manifest::EXTERNAL_PREF_DOWNLOAD, 458 extensions::Extension::FROM_WEBSTORE | 459 extensions::Extension::WAS_INSTALLED_BY_DEFAULT)); 460 461 EXPECT_CALL(visitor, OnExternalExtensionFileFound(_, _, _, _, _, _)) 462 .Times(0); 463 EXPECT_CALL(visitor, OnExternalExtensionUpdateUrlFound(_, _, _, _, _, _)) 464 .Times(0); 465 EXPECT_CALL(visitor, OnExternalProviderReady(_)) 466 .Times(1); 467 468 // Manually request a load. 469 loader->StartLoading(); 470 Mock::VerifyAndClearExpectations(&visitor); 471 472 EXPECT_CALL(visitor, OnExternalExtensionFileFound(_, _, _, _, _, _)) 473 .Times(0); 474 EXPECT_CALL(visitor, OnExternalExtensionUpdateUrlFound(_, _, _, _, _, _)) 475 .Times(0); 476 EXPECT_CALL(visitor, OnExternalProviderReady(_)) 477 .Times(1); 478 479 RunUntilIdle(); 480 EXPECT_TRUE(doc->IsReady()); 481 } 482 483 } // namespace chromeos 484